2

次のコードに問題があります。

trait HelloPhrase {
    fn hello(&self, to: &'static str);
}

pub enum GetHelloResult<H: HelloPhrase> {
    Matched(H),
    NoMatch,
}

struct English;

impl English {
    pub fn new() -> English {
        English
    }
}

impl HelloPhrase for English {
    fn hello(&self, to: &'static str) {
        println!("Hello {}.", to)
    }
}

struct Phrases<H: HelloPhrase> {
    hello_phrases: std::collections::HashMap<&'static str, H>,
}

impl<H: HelloPhrase> Phrases<H> {
    pub fn new() -> Phrases<H> {
        Phrases { hello_phrases: std::collections::HashMap::new() }
    }

    pub fn add_hello_phrase(&mut self, lang: &'static str, hello_phrase: H) {
        self.hello_phrases.insert(lang, hello_phrase);
    }

    pub fn get_hello(&self, lang: &'static str) -> GetHelloResult<H> {
        match self.hello_phrases.get(lang) {
            Some(hello_phrase) => return GetHelloResult::Matched(hello_phrase),
            _ => return GetHelloResult::NoMatch,
        };
    }
}

fn main() {
    let mut hs = Phrases::new();
    hs.add_hello_phrase("english", English::new());

    match hs.get_hello("english") {
        GetHelloResult::Matched(hello_phrase) => hello_phrase.hello("Tom"),
        _ => println!("HelloPhrase not found"),
    }
}

(再生リンク)

HelloPhrase実装する言語、英語、ロシア語などの特性です。Phrasesマネージャー構造体であり、言語からフレーズへの多くのマップを持つことができます。これは不自然な例ですが、これをイベント マネージャー (つまり、X 入力のイベント ハンドラーを取得する)、または HTTP ハンドラーおよびルーターと考えることができます。

そうは言っても、 a の所有権を借りHelloPhraseて呼び出し元に返す方法を理解するのに苦労しています。実行すると、次のエラーが返されます。

<anon>:40:66: 40:78 error: mismatched types:
 expected `H`,
    found `&H`
(expected type parameter,
    found &-ptr) [E0308]
<anon>:40             Some(hello_phrase) => return GetHelloResult::Matched(hello_phrase),
                                                                           ^~~~~~~~~~~~

私は追加しようとしました:

pub fn get_hello(&self, lang: &'static str) -> GetHelloResult<&H> {

pub enum GetHelloResult<H: HelloPhrase> {
    Matched(&H),
    NoMatch,
}

(再生リンク)

次のエラーが発生します。

<anon>:7:13: 7:15 error: missing lifetime specifier [E0106]
<anon>:7     Matched(&H),

列挙型にライフタイムを追加するのに問題があります-理論的には、戻り値のライフタイムを構造体のライフタイムにしたいのですPhrasesが、ライフタイムの構文はこれまでのところ非常に混乱しています。これを 2 つの質問にまとめると、次のようになります。

  1. GetHelloResultこのエラーを満たすために、 にライフタイムを追加するにはどうすればよいですか?
  2. Rust の所有規則に基づいて、Rust でアンチパターンを実行しようとしていますか? このようなものには、どのようなデザインが適しているでしょうか?

ドキュメントに基づいて、構造体でライフタイムを使用する方法は知っていますが、列挙型にライフタイムを追加する方法はわかりません (構文に関して)。構造体の有効期間についてだけ言及したのは、それが欠けている部分だと思うからですが、正直なところわかりません。hello_phrasesさらに、構造体と実装にライフタイムを追加してマップに追加しようとすると、エラーが発生します

the parameter type `H` may not live long enough [E0309]
4

2 に答える 2

3

ここでの混乱は、ライフタイム省略の残念な副作用です。99% のケースで役に立ちますが、あまり見つけられません。

GetHelloResult生涯で注釈を付ける必要があります:

pub enum GetHelloResult<'a, H: 'a + HelloPhrase> {
    Matched(&'a H),
    NoMatch,
}

pub fn get_hello(&self, lang: &'static str) -> GetHelloResult<H> {
    match self.hello_phrases.get(lang) {
        Some(hello_phrase) => return GetHelloResult::Matched(hello_phrase),
        _ => return GetHelloResult::NoMatch,
    };
}

GetHelloResultこれにより、構造体の存続期間が構造体の存続Phrases期間に結び付けられるため、Phrases構造体が変更 (または破壊) された場合、返された参照は無効になります。この場合、寿命は と同じであると推測されますself。これは、読んでも明らかではありませんが、本当です! 明らかでない状況では、 を使用して明示的に注釈を付けたい場合がありますGetHelloResult<'a, H>

リンクを再生します。

于 2016-04-11T19:46:18.687 に答える
2

参照 ( ) を返す場合fn get_hello(&self, lang: &'static str) -> GetHelloResult<&H>、その特性を実装する型への参照の特性を実装する限り、コードは正常に機能します。

impl<'a, H> HelloPhrase for &'a H 
    where H: HelloPhrase
{
    fn hello(&self, to: &'static str) {
        (**self).hello(to)
    }
}
于 2016-04-11T19:51:04.553 に答える