【问题标题】:Rust options, implementing a custom "expect" methodRust 选项,实现自定义的“期望”方法
【发布时间】:2015-04-05 13:08:11
【问题描述】:

我对 Rust 很陌生,所以我必须警告你,我不是 100% 确定我在做什么。在一个 rust-sfml 示例(与问题无关)中,我看到了这个选项模式,这显然是一个常见的模式:

let ballSoundBuffer = match SoundBuffer::new("resources/ball.wav") {
    Some(ballSoundBuffer)   => ballSoundBuffer,
    None                    => panic!("Cannot load Ball sound buffer.")
};

后来我了解了expect()函数,所以上面可以替换为:

 let ballSoundBuffer = SoundBuffer::new("resources/ball.wav").expect("Cannot load Ball sound buffer.")

为了练习,我想自己实现类似 expect 方法的东西,作为一个独立的方法,并想出了这样的东西:

fn checkOption<T>(obj: Option<T>, err: &str) -> T {
    match obj {
        Some(o) => return o,
        None => panic!(err)
    }
}

我们的目标是:

let tmp = SoundBuffer::new("resources/ball.wav");
let ballSoundBuffer = checkOption(tmp, "Cannot load Ball sound buffer.");

我使用泛型是因为我还希望该方法与 SoundBuffer 以外的其他资源一起使用(但它们在加载它们时也使用相同的选项模式)。但是,这根本不起作用:

src/main.rs:20:24: 20:27 error: cannot infer an appropriate lifetime due to conflicting requirements
src/main.rs:20         None => panic!(err)
                                  ^~~
<std macros>:1:1: 12:62 note: in expansion of panic!
src/main.rs:20:17: 21:6 note: expansion site
src/main.rs:17:51: 22:2 note: first, the lifetime cannot outlive the anonymous lifetime #1 defined on the block at 17:50...
src/main.rs:17 fn checkOption<T>(obj: Option<T>, err: &str) -> T {
src/main.rs:18     match obj {
src/main.rs:19         Some(o) => return o,
src/main.rs:20         None => panic!(err)
src/main.rs:21     }
src/main.rs:22 }
src/main.rs:20:24: 20:27 note: ...so that expression is assignable (expected `&str`, found `&str`)
src/main.rs:20         None => panic!(err)
                                  ^~~
<std macros>:1:1: 12:62 note: in expansion of panic!
src/main.rs:20:17: 21:6 note: expansion site
note: but, the lifetime must be valid for the static lifetime...
<std macros>:3:1: 3:28 note: ...so that the type `&str` will meet its required     lifetime bounds
<std macros>:3 $ crate:: rt:: begin_unwind (
           ^~~~~~~~~~~~~~~~~~~~~~~~~~~
<std macros>:1:1: 12:62 note: in expansion of panic!
src/main.rs:20:17: 21:6 note: expansion site
error: aborting due to previous error

我不知道该怎么办 :( 我希望有更多知识的人能指出我的错误。

感谢您的宝贵时间!

【问题讨论】:

  • 我向panic! 提交了关于使用非字符串作为第一个参数的糟糕错误消息的issue a while back

标签: rust lifetime


【解决方案1】:

有几种方法可以修复你的函数:第一种是在err上添加'static生命周期注解:

fn checkOption<T>(obj: Option<T>, err: &'static str) -> T {
    match obj {
        Some(o) => return o,
        None => panic!(err)
    }
}

但是,这意味着您只能将&amp;'static str 类型的值(即字符串常量,实际上)用于err

第二种方法是做expect所做的事情并调用panic!("{}", err)而不是panic!(err)

fn checkOption<T>(obj: Option<T>, err: &str) -> T {
    match obj {
        Some(o) => return o,
        None => panic!("{}", err)
    }
}

【讨论】:

    【解决方案2】:

    哦,我在发布前搜索了几个小时,当然我在发布后 5 分钟发现了问题:

    panic!(err) 必须是 panic!("{}", err)

    也许是因为我太新了,但是那个错误消息非常令人困惑......

    【讨论】:

    • 是的,错误信息很糟糕。我只是很快弄清楚了,因为我隐约记得恐慌消息需要是Send,而&amp;str 不是Send。从技术上讲,它拥有所有信息,但它隐藏在可怕而冗长的绒毛中。也许在 Github 上提出问题。
    【解决方案3】:

    似乎panic! 需要提供给它的字符串才能具有静态生命周期。

    将您的签名更改为 fn checkOption&lt;T&gt;(obj: Option&lt;T&gt;, err: &amp;'static str) -&gt; T 编译并执行您想要的操作。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2021-05-14
      • 1970-01-01
      • 2017-06-07
      • 2015-01-08
      • 1970-01-01
      • 1970-01-01
      • 2011-05-30
      • 1970-01-01
      相关资源
      最近更新 更多