Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Rust options, implementing a custom "expect" method

Tags:

rust

lifetime

I'm very new to Rust, so I must warn you, I'm not 100% sure what I'm doing. In a rust-sfml example (irrelevant to question) I saw this Options pattern which is apparently a common one:

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

Later I learned about the expect() function so the above can be replaced with:

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

For the sake of exercise I wanted to implement something like the expect method myself, as a standalone method, and came up with something like this:

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

The goal was to do something like:

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

I'm using generics because I also want the method to work with other resources than SoundBuffer (but they also use the same Options pattern when loading them). However, this doesn't work at all:

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

I have no idea what to do with this :( I was hoping someone more knowledgeable could point out my mistake.

Thanks for your time!

like image 969
peanutman Avatar asked Mar 17 '23 12:03

peanutman


1 Answers

There are several ways to fix your function: The first is to add a 'static lifetime annotation on err:

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

However, this means you can only use values of type &'static str (i.e. string constants, effectively) for err.

The second way is to do what expect does and call panic!("{}", err) instead of panic!(err):

fn checkOption<T>(obj: Option<T>, err: &str) -> T {
    match obj {
        Some(o) => return o,
        None => panic!("{}", err)
    }
}
like image 146
fjh Avatar answered Mar 31 '23 13:03

fjh