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生命周期是结构的生命周期——但到目前为止,生命周期语法对我来说相当混乱。总结为两个问题:

  1. 如何添加生命周期GetHelloResult来满足这个错误?
  2. 基于 Rust 的所有权规则,我试图用 Rust 做一个反模式吗?对于这样的事情,什么可能是更好的设计?

根据文档,我知道如何在结构上使用生命周期,但我不知道如何为枚举添加生命周期(语法方面)。我只提到了结构生命周期,因为我认为这是一个缺失的部分,但老实说我不知道​​。此外,如果我向 struct 和 impl 添加生命周期并尝试将其添加到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 回答