Why can't `Self` be used to refer to an enum's variant in a method body?

后端 未结 5 1978
无人及你
无人及你 2020-12-11 15:20

This question is now obsolete because this feature has been implemented. Related answer.


The following Rust code fails to compile:

enum Foo {
          


        
相关标签:
5条回答
  • 2020-12-11 15:51

    If the enum name Foo is in reality long and you want to avoid repeating it across the implementation, you have two options:

    • use LongEnumName as Short at module level. This will allow you to return Short::Bar at the end of f.
    • use LongEnumName::* at module level, allowing an even shorter Bar.

    If you omit pub, the imports will be internal and won't affect the public API of the module.

    0 讨论(0)
  • 2020-12-11 15:58

    An important thing to note is that the error said associated item. enum Foo { Baz } doesn't have associated items. A trait can have an associated item:

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

    To summarize:

    Why can't Self be used in this situation?

    Because of this issue. RFC 2338 has not been implemented yet.

    Self seems to act as a type alias, albeit with some modifications.

    Where exactly can Self be used?

    Self can only be used in traits and impls. This code:

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

    Outputs the following:

    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
    

    This is possibly a temporary situation and might change in the future!

    More precisely, Self should be used only as part of method signature (e.g. fn self_in_self_out(&self) -> Self) or to access an associated type:

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

    I think user4815162342 covered the rest of the answer best.

    0 讨论(0)
  • 2020-12-11 16:04

    Enum constructors != associated items.

    It is a known issue, but it's not expected to be fixed, at least not in the foreseeable future. From what I have gathered it is not trivial to just allow this to work; at this point it is more likely that the related documentation or the error message will be improved.

    There is little documentation I could find on the topic of associated items in general; The Rust Book has a chapter on associated types, though. In addition, there are plenty of good answers about Self in this related question.

    0 讨论(0)
  • 2020-12-11 16:14

    There is an experimental feature that would make your example work without any other changes. You can try it out in a nightly build of Rust by adding this in your main file:

    #![feature(type_alias_enum_variants)]
    

    You can follow the progress of the feature towards stabilisation in its tracking issue.

    0 讨论(0)
  • 2020-12-11 16:17

    This is now possible as of version 1.37.

    0 讨论(0)
提交回复
热议问题