在crate的API中发布具体类型而不是`impl trait`有什么好处?

riv*_*ivy 6 rust

在修补一个箱子,我把它放在自己隐藏内部迭代器类型,但作者说,出版类型是一个功能,那最好的做法是公布一个明确的包装结构的公共API中暴露的每一个迭代器.显然,Rust标准库为它的所有迭代器都做了这个.

为什么这样?更具体地说,如果实现一个兼容的类型,std::env::Args使用的优缺点是什么......

// implement iterator compatible with std::env::Args
pub struct Args { // public
    // pub(crate) ...
}

impl Iterator for Args {
    // ...
}

pub fn args() -> Args {
    // ...
    // return Args
}
Run Code Online (Sandbox Code Playgroud)

VS

// implement iterator compatible with std::env::Args
pub(crate) struct Args { // hidden (outside of crate)
    // pub(crate) ...
}

impl Iterator for Args {
    // ...
}

pub fn args() -> impl Iterator<Item = String> {
    // ...
    // return Args
}
Run Code Online (Sandbox Code Playgroud)

She*_*ter 9

从来没有一个真正的最佳实践.

返回具体类型的原因包括:

  1. 您当前无法声明类型变量impl Trait,因此必须推断出任何此类用法.出于同样的原因,这些不容易放在结构中.

  2. 您不能将固有方法添加到impl Trait返回类型.例如,Charsas_str方法.

  3. 正如trentcl指出的那样,impl Trait不能有条件地实现特性.这对于迭代器适配器很重要Skip.

  4. 你陈述"兼容std::env::Args",但这里有Args实现的特征:

    impl Iterator for Args {}
    impl ExactSizeIterator for Args {}
    impl DoubleEndedIterator for Args {}
    impl Debug for Args {}
    
    Run Code Online (Sandbox Code Playgroud)

    您的界面不允许其中的四个.作为一个例子,你的API的消费者不能再从后面迭代了.您可以通过执行此操作来解决此问题impl Iterator<Item = String> + DoubleEndedIterator + ExactSizeIterator + Debug,但无论如何,您实际上都有自己的类型.如果在现有迭代器上返回newtype,也可能出现此问题,这就是为什么我需要更好的委派语法.

另请参阅C-NEWTYPE-HIDE API指南.

Rust标准库为其所有迭代器执行此操作

标准库中的迭代器是在impl Trait存在之前创建的,因此没有其他选择.由于向后兼容性,它们现在无法更改为不再返回具体类型.

  • 许多标准库迭代器适配器*可能会或可能不会*实现其他特征,具体取决于原始迭代器是否支持.例如,`iter.map(f)`是一个迭代器,当且仅当`iter`实现`DoubleEndedIterator`时才实现`DoubleEndedIterator`.你无法使用`impl Trait`以这种方式定义`map` (2认同)
  • 将`fn foo() - > impl Iterator`转换为`fn foo() - > impl Iterator + Debug + DoubleEndedIterator是不是一个突破性的变化? (2认同)