在板条箱的API中发布具体类型而不是“ impl trait”的好处是什么?

时间:2018-08-29 14:30:18

标签: 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
}

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
}

1 个答案:

答案 0 :(得分:8)

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

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

  1. 您当前无法声明类型为impl Trait的变量,因此必须推断出任何此类用法。出于相同的原因,不能轻易将它们放置在结构中。

  2. 您不能将固有方法添加到impl Trait返回类型中。例如,Chars具有as_str方法。

  3. trentcl points out一样,impl Trait无法有条件地实现特征。这对于Skip之类的迭代器适配器来说很重要。

  4. 您声明“与std::env::Args兼容”,但这是Args实现的特征:

    impl Iterator for Args {}
    impl ExactSizeIterator for Args {}
    impl DoubleEndedIterator for Args {}
    impl Debug for Args {}
    

    您的界面不允许使用这四个中的三个。作为一个例子,您的API的使用者不能再从后面进行迭代。您可以通过执行impl Iterator<Item = String> + DoubleEndedIterator + ExactSizeIterator + Debug来解决此问题,但是无论如何在某种程度上您还是拥有自己的类型。如果您在现有迭代器上返回新类型,也可能会出现此问题,这就是为什么我想要更好的委托语法。

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

  

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

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