【问题标题】:Why can't `Self` be used to refer to an enum's variant in a method body?为什么不能使用“Self”来引用方法体中的枚举变量?
【发布时间】:2018-03-05 22:14:27
【问题描述】:

这个问题现在已经过时了,因为这个功能已经实现了。 Related answer.


以下 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
    }
}

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

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

【问题讨论】:

  • 枚举有点奇怪,因为它们介于类型和命名空间之间。在这种情况下,Foo 更像是一个命名空间。也就是说,这只是出于好奇,还是阻止了你做你想做的事情?
  • @PaoloFalabella 这里Self的常用用法是减少类型名称的重复。我只是希望我可以在方法体中做同样的事情。
  • 我遇到了一些好文章,users.rust-lang.org/t/…。希望对你有所帮助。
  • 这个问题是关于以前缺少的功能现在存在的,所以它不再相关。

标签: enums rust


【解决方案1】:

需要注意的重要一点是错误表示关联项。 enum Foo { Baz } 没有关联的项目。一个特征可以有一个关联的项目:

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

总结一下:

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

因为this issueRFC 2338not been implemented yet

Self 似乎充当类型别名,尽管有一些修改。

Self具体可以用在哪里?

Self 只能用于traits 和impls。这段代码:

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

【讨论】:

    【解决方案2】:

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

    • use LongEnumName as Short 在模块级别。这将允许您在 f 的末尾返回 Short::Bar
    • use LongEnumName::* 在模块级别,允许更短的Bar

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

    【讨论】:

      【解决方案3】:

      version 1.37 开始,这现在可以实现了。

      【讨论】:

        【解决方案4】:

        枚举构造函数!= 关联项。

        这是一个已知的issue,但预计不会修复,至少在可预见的将来不会。从我收集到的信息来看,让它发挥作用并非易事。此时更有可能改进相关文档或错误消息。

        我几乎找不到关于关联项目主题的文档一般;不过,Rust Book 有一章是关于 associated types 的。另外,this related question中有很多关于Self的好答案。

        【讨论】:

          【解决方案5】:

          有一个experimental feature 可以使您的示例在没有任何其他更改的情况下工作。你可以通过在你的主文件中添加这个来在 Rust 的夜间构建中试用它:

          #![feature(type_alias_enum_variants)]
          

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

          【讨论】:

            猜你喜欢
            • 1970-01-01
            • 2017-07-06
            • 1970-01-01
            • 2016-02-13
            • 1970-01-01
            • 1970-01-01
            • 2018-10-25
            • 2011-10-22
            • 1970-01-01
            相关资源
            最近更新 更多