【问题标题】:Possible bug in generic implementation of Default? [duplicate]默认的通用实现中可能存在错误? [复制]
【发布时间】:2017-09-06 16:10:40
【问题描述】:

给定以下派生Default的结构Foo<T>

#[derive(Default)]
struct Foo<T> {
    bar: Option<T>,
}

为什么会编译

fn create<T>() -> Foo<T> {
    Foo {
        bar: Option::default(),
    }
}

但这不是?

fn create_alt<T>() -> Foo<T> {
    Foo::default()
}

在我看来,它们都在做完全相同的事情——T 是否实现 Default(这是编译器要我指定的)无关紧要,因为 Option&lt;T&gt; 实现了 Default

Here 是指向 Rust Playground 与此示例的链接。

【问题讨论】:

  • 请注意,这发生在其他几个可自动派生的特征上,包括DebugDefaultClone,可能还有更多。派生实现要求所有类型参数也实现它们。

标签: rust traits


【解决方案1】:

这是一个已知问题,很难修复。 Issue #26925

简而言之,#[derive] 使用了不正确的界限:它假定为了实现 DefaultFoo&lt;T&gt;T 必须是 Default,而实际上 Option&lt;T&gt;: Default 就足够了。

修复它的问题是它可能具有私有类型的结构成员,并且在具有私有成员的公共通用结构上使用#[derive] 可能会部分公开该私有接口。例如,

trait MyTrait {}

struct MyType<T> {}

impl<T> Default for MyType<T> where T: MyTrait {}

#[derive(Default)]
pub struct PubType<T> {
    member: MyType<T>,
}

如果#[derive(Default)] 做正确的事,那么您实际上拥有这个impl 块,用于公开私有特征的公共类型:

impl Default for PubType<T>
    where T: MyTrait
{ ... }

目前解决此问题的最佳方法可能是在这种情况下避免使用#[derive],而自己编写impl

【讨论】:

    猜你喜欢
    • 2016-07-02
    • 1970-01-01
    • 1970-01-01
    • 2020-05-07
    • 2019-06-19
    • 1970-01-01
    • 1970-01-01
    • 2012-08-30
    • 2012-06-22
    相关资源
    最近更新 更多