为什么不能使用`Self`来引用方法体中的枚举变体?

时间:2017-09-25 02:29:32

标签: enums rust

以下Rust代码无法编译:

enum Foo {
    Bar,
}

impl Foo {
    fn f() -> Self {
        Self::Bar
    }
}

错误消息让我感到困惑:

error[E0599]: no associated item named `Bar` found for type `Foo` in the current scope
 --> src/main.rs:7:9
  |
7 |         Self::Bar
  |         ^^^^^^^^^

使用Foo代替Self可以解决问题,但这让我很奇怪,因为Self应该引用正在实现的类型(忽略特征) ,在这种情况下是Foo

enum Foo {
    Bar,
}

impl Foo {
    fn f() -> Self {
        Foo::Bar
    }
}

为什么在这种情况下不能使用Self?究竟可以使用Self * ?还有什么我可以用来避免在方法体中重复类型名称吗?

* 我忽略了traits中的用法,其中Self指的是实现特征的任何类型。

5 个答案:

答案 0 :(得分:6)

需要注意的一件重要事情是错误表示相关项目。 enum Foo { Baz }没有关联商品。特质可以有一个相关的项目:

trait FooBaz { type Baz }
//             ^~~~~~~~ - associated item

总结:

  

为什么在这种情况下不能使用Self

因为this issueRFC 2338not been implemented yet

Self似乎是一个类型别名,虽然有一些修改。

  

究竟可以使用Self吗?

自我只能用于特征和impl。这段代码:

struct X {
    f: i32,
    x: &Self,
}

输出以下内容:

error[E0411]: cannot find type `Self` in this scope
 --> src/main.rs:3:9
  |
3 |     x: &Self,
  |         ^^^^ `Self` is only available in traits and impls

这可能是暂时的情况,将来可能会发生变化!

更确切地说,Self应仅用作方法签名的一部分(例如fn self_in_self_out(&self) -> Self)或访问相关类型:

enum Foo {
    Baz,
}

trait FooBaz {
    type Baz;

    fn b(&self) -> Self::Baz; // Valid use of `Self` as method argument and method output
}


impl FooBaz for Foo {
    type Baz = Foo;

    fn b(&self) -> Self::Baz {
        let x = Foo::Baz as Self::Baz; // You can use associated type, but it's just a type
        x
    }
}

我认为user4815162342 covered the rest of the answer best

答案 1 :(得分:4)

如果枚举名Foo实际上很长,并且您希望避免在整个实现中重复它,那么您有两个选择:

    模块级别的
  • use LongEnumName as Short。这样您就可以在Short::Bar结束时返回f
  • 在模块级别
  • use LongEnumName::*,允许更短的Bar

如果省略pub,导入将是内部的,不会影响模块的公共API。

答案 2 :(得分:2)

枚举构造函数!=相关项目。

这是一个众所周知的issue,但预计不会被修复,至少在可预见的未来不会。从我收集的内容来看,让这个工作起来并不是一件容易的事。此时,相关文档或错误消息更有可能得到改进。

关于相关项的主题,我几乎找不到文档。然而,Rust Book有一章associated types。此外,this related question中的Self有很多好的答案。

答案 3 :(得分:1)

有一个experimental feature,可以使您的示例正常运行而无需进行其他任何更改。您可以通过在主文件中添加以下内容,在每晚的Rust版本中进行尝试:

#![feature(type_alias_enum_variants)]

您可以在其tracking issue中关注该功能向稳定化的进度。

答案 4 :(得分:1)

version 1.37开始,这是可能的。