Why can't "Self" be used to indicate an enumeration option in the method body?

This question is now outdated because this function has been implemented. Related answer .


The following Rust code does not compile:

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

The error message confuses me:

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

The problem can be fixed using Foo instead of Self , but this seems strange to me, because Self should refer to the type being implemented (ignoring traits), which in this case is Foo .

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

Why not use Self in this situation? Where exactly can I use Self * ? Can anything else be used to avoid duplicating the type name in the body of the method?

* I'm ignoring usage in traits, where [TG49] refers to whatever type implements the trait.

+13
enums rust
source share
5 answers

It is important to note that the related item is mentioned in the error message. enum Foo { Baz } has no related items. A trait can have an associated element:

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

To summarize:

Why not use Self in this situation?

Due to this problem . RFC 2338 has not yet been implemented .

It seems that Self acts as a type alias, albeit with some modifications.

Where exactly can I use Self ?

The self can only be used in traits and impl . 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 

Perhaps this is a temporary situation and may change in the future!

More precisely, Self should be used only as part of the method signature (for example, fn self_in_self_out(&self) → Self ) or to access a related 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 just a type x } } 

I think user4815162342 covered the rest of the answer best .

+6
source share

If the enumeration name Foo is actually long, and you want to avoid repeating it in 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 the module level, which makes Bar even shorter.

If you omit the pub , the import will be internal and will not affect the open module API.

+4
source share

Constructors Enum! = Related elements.

This is a known issue , but it is not expected to be fixed, at least in the foreseeable future. From what I have assembled, it is easy to just let it work; at the moment, it is more likely that the related documentation or error message will be improved.

There is a little documentation that I could find on related items in general; However, the Rust Book has a chapter on related types . In addition, there are many good answers about Self in this related question .

+2
source share

There is an experimental function that will allow your example to work without any other changes. You can try it in the nightly build of Rust by adding this to your main file:

 #![feature(type_alias_enum_variants)] 

You can track the progress of a function toward stabilization in its tracking problem .

+1
source share

Now it is possible starting from version 1.37 .

+1
source share

All Articles