rust-lang/rust-clippy

Suggest to replace impl Iterator return types with wrapper types

Open

#5,989 建立於 2020年8月31日

在 GitHub 查看
 (2 留言) (0 反應) (1 負責人)Rust (1,391 fork)batch import
A-lintL-restrictionT-middlegood first issue

倉庫指標

Star
 (10,406 star)
PR 合併指標
 (平均合併 16天 6小時) (30 天內合併 79 個 PR)

描述

What it does

It suggests replacing impl Iterator with a wrapper type, if the function is public (other crates can call it).

The impl Trait syntax erases types completely, which makes it impossible to use them as struct fields. This can make the API of a crate less convenient, because you have to for example collect the returned Iterator into a Vec (function_returns_impl_iterator().collect::<Vec<_>>()).

The syntax should be mainly used for situations, where you cannot represent the returned value as a concrete type.

For example

use std::future::Future;

async fn hello() -> impl Future<Output = &'static str> { "hello" }

this function can only return impl Future, because there is no type for the returned value.

What is the advantage of the recommended code over the original code

The returned value can be used by other structs as fields or it could be used with functions that have bounds like this:

fn takes_iterator<I: Iterator<Item=usize>>(iterator: I);

Example

original code:

#![warn(clippy::pedantic, clippy::nursery)]

use std::iter::Iterator;

fn greetings() -> impl Iterator<Item = (usize, &'static str)> {
    vec!["hello", "hallo", "salut", "hola", "ciao"]
        .into_iter()
        .enumerate()
}

fn main() {
    for (number, greeting) in greetings() {
        println!("{}\t=> {:?}", number, greeting);
    }
}

better code

#![warn(clippy::pedantic, clippy::nursery)]

use std::iter::Iterator;

pub struct IntoIter(pub(crate) std::iter::Enumerate<std::vec::IntoIter<&'static str>>);

impl Iterator for IntoIter {
    type Item = (usize, &'static str);

    fn next(&mut self) -> Option<Self::Item> {
        self.0.next()
    }
}

fn greetings() -> IntoIter {
    IntoIter(
        vec!["hello", "hallo", "salut", "hola", "ciao"]
            .into_iter()
            .enumerate(),
    )
}

fn main() {
    for (number, greeting) in greetings() {
        println!("{}\t=> {:?}", number, greeting);
    }
}

Drawbacks

Writing wrapper types can result in quite a lot of boilerplate code that might not be worth the time, because almost every downstream crate would just iterate over the returned value. Therefore, I suggest making this lint pedantic.

This lint can not be applied to every usage of impl Trait, so I would suggest limiting it to Iterator (can be extended in the future).

Categories (optional)

  • clippy::style
  • clippy::pedantic

貢獻者指南