Passing mutable context into callbacks

杀马特。学长 韩版系。学妹 提交于 2019-12-06 03:46:54

These deep lifetime issues are hairy, so let's see if we can figure it out. Let's start with a look at a stripped-down version of the code that has the same error:

struct RunLoop<'a> {
    marker: &'a u8,
}

struct MyContext<'a> {
    rl: &'a mut RunLoop<'a>,
}

fn run(rl: &mut RunLoop) {
    let mut ctxt = MyContext { rl: rl };
}

fn main() {}

The definition of MyContext states that it needs to be provided a reference to a RunLoop. The lifetime of the RunLoop and the lifetime the RunLoop is parameterized with need to be unified - they are both set to 'a. However, this cannot be guaranteed based on the signature of run. All that is known is that there are two lifetimes, both elided at the moment.

This leads to one solution: we can explicitly identify both lifetimes and establish a relationship between them:

struct MyContext<'a, 'b : 'a> {
    rl: &'a mut RunLoop<'b>,
}

Another solution is the one hinted at by the compiler: pre-unify the lifetimes when run has been called:

fn run<'a>(rl: &'a mut RunLoop<'a>) {

However, this latter solution doesn't work in the larger program, failing with:

error: mismatched types [--explain E0308]
  --> src/main.rs:74:27
74 |>     rl.register(("l_run", MyWidget::l_run));
   |>                           ^^^^^^^^^^^^^^^ expected concrete lifetime, found bound lifetime parameter
note: expected type `fn(&mut RL<'_>)`
note:    found type `fn(&'a mut RL<'a>) {MyWidget::l_run}`
note: expected concrete lifetime is lifetime ReSkolemized(0, BrAnon(0))

(Side note: it's been a long time since I've seen a ReSkolemized mention in an error message!)

Let's extend our small example to generate the same error:

struct RunLoop<'a> {
    marker: &'a u8,
}

struct MyContext<'a> {
    rl: &'a mut RunLoop<'a>,
}

fn run<'a>(rl: &'a mut RunLoop<'a>) {
    let mut ctxt = MyContext { rl: rl };
}

fn register(func: fn(&mut RunLoop)) {}

fn main() {
    register(run);
}

This I'm less sure about. I do know that putting just about any explicit lifetime on the reference helps it compile:

fn register<'a>(func: fn(&'a mut RunLoop<'a>)) {}
fn register<'a, 'b>(func: fn(&'a mut RunLoop<'b>)) {}
fn register(func: fn(&'static mut RunLoop)) {}
标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!