2017-09-25 72 views
7

Poniższy kod Rust nie kompilacji:Dlaczego `Self` nie może być użyty w odniesieniu do wariantu wyliczeniowego w treści metody?

enum Foo { 
    Bar, 
} 

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

Komunikat o błędzie mnie dezorientuje:

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

Problemem mogą być mocowane za pomocą Foo zamiast Self, ale wydaje mi się dziwne, ponieważ Self ma odnosić się do wprowadzanego typu (ignorowanie cech), który w tym przypadku jest Foo.

enum Foo { 
    Bar, 
} 

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

Dlaczego w tej sytuacji nie można zastosować Self? Gdzie dokładnie można użyć Self*? Czy jest coś jeszcze, czego mogę użyć, aby uniknąć powtarzania nazwy typu w treści metody?

* Ignoruję użycie w cechach, gdzie Self odnosi się do dowolnego typu implementuje tę cechę.

+0

Wyliczenia są nieco dziwne, ponieważ działają między typami i przestrzeniami nazw. W tym przypadku Foo działa bardziej jako przestrzeń nazw. To powiedziawszy, czy to tylko ciekawość, czy to uniemożliwia ci zrobienie czegoś, co chciałbyś robić? –

+0

@PaoloFalabella Powszechnym użyciem 'Self' jest tutaj zmniejszenie liczby powtórzeń nazwy typu. Miałem tylko nadzieję, że mogłem zrobić to samo w ciałach metod. – Challenger5

+0

Natknąłem się na jakiś dobry artykuł, https://users.rust-lang.org/t/confused-by-use-of-self-in-example-in-chapter17-of-rust-book-2nd- edycja/11394. Mam nadzieję, że może ci pomóc. – shri

Odpowiedz

0

Konstruktory Enum! = Powiązane elementy.

Jest to znany issue, ale nie należy go naprawiać, przynajmniej nie w przewidywalnej przyszłości. Z tego, co zebrałem, nie jest łatwe, aby pozwolić na to, by działało; w tym momencie jest bardziej prawdopodobne, że poprawiona zostanie powiązana dokumentacja lub komunikat o błędzie.

Istnieje niewiele dokumentacji, które można znaleźć na temat powiązanych elementów ogólnie; The Rust Book ma jednak rozdział o associated types. Ponadto istnieje wiele dobrych odpowiedzi na temat Self w this related question.

1

Jeśli nazwa enum Foo w rzeczywistości jest długa i chcesz uniknąć powtarzania go przez życie, masz dwie opcje:

  • use LongEnumName as Short na poziomie modułu. To pozwoli ci zwrócić Short::Bar pod koniec f.
  • use LongEnumName::* na poziomie modułu, umożliwiając jeszcze krótszy Bar.

Jeśli pominiesz pub, import będzie wewnętrzny i nie wpłynie na publiczny interfejs API modułu.

1

Ważną rzeczą, na którą należy zwrócić uwagę, jest błąd związany z wymienionym elementem. enum Foo { Baz } nie ma powiązanych produktów. Cechą może mieć przypisaną przedmiot:

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

Podsumowując:

Dlaczego nie Self może być stosowany w tej sytuacji?

Z powodu this issue.

Self wydaje się działać jako alias typu, aczkolwiek z pewnymi modyfikacjami.

Gdzie dokładnie można użyć Self?

Własna może być używana tylko w cechach i impl s. Ten kod:

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

Wyjścia następujące:

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 

Jest to prawdopodobnie sytuacja tymczasowa i może ulec zmianie w przyszłości!

Dokładniej, należy stosować Self tylko część podpisu metodą (np fn self_in_self_out(&self) -> Self) lub dostępu przypisany typ:

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

myślę user4815162342 covered the rest of the answer best.