参考生命周期与相同的生命周期范围冲突

时间:2017-02-08 06:26:00

标签: rust lifetime

我试图在Rust中存储和使用一个可选的回调句柄,它就像我存储它的结构的方法一样。只要我没有将对它自己的引用传递给回调,它就可以工作。但这样做会给使用对象引用(E0312)带来生命周期错误。生命似乎是相同的,我无法弄清楚要改变什么来使这个工作。

type Callback<'a> = Fn(&'a mut Func, i32) -> i32;

struct Func<'a> {
    val: i32,
    func: Option<Box<Callback<'a>>>,
}

impl<'a, 'b> Func<'b> {
    fn exec(&'a mut self, val: i32) -> i32 {
        if let Some(ref f) = self.func {
            return f(self, val);
        };
        0i32
    }
}

fn main() {
    let mut a32 = Func{
        val: 10i32,
        func: Some(Box::new(|ref mut s, val: i32| -> i32 {
            let v = s.val;
            s.val += 1;
            val * 32 + v
        }))
    };
    println!("a32(4) = {}", a32.exec(4i32));
    println!("a32(4) = {}", a32.exec(4i32));
}

有没有办法解决这个问题,还是我遇到了编译器错误?

使用rustc 1.15.0(10893a9a3 2017-01-19)。

另见Rust playground

我也尝试过没有明确的生命周期,但后来我遇到了一个问题,我不能在Rust(E0502)中为别名引用。

我知道Rust试图阻止这种情况以避免数据争用,但这是否意味着我总是需要在这些情况下创建我的对象的副本?
以下不能给我一个错误,借来的内容无法移出(E0507)。

impl Func {
    fn exec(&mut self, val: i32) -> i32 {
        if self.func.is_some() {
            return self.func.unwrap()(self, val);
        };
        0i32
    }
}

但我找不到克隆盒装函数的方法......

1 个答案:

答案 0 :(得分:2)

你在这里有借款问题:

  1. 您正在借助self.func不可变的
  2. 您正在尝试同时借用self
  3. 这是不允许的,因为它可以让你在使用时更改func,这预示着麻烦。

    您可以尝试将Callback更改为仅传入&mut i32,但之后您会遇到终身统一问题:

    • 如果您指定exec需要&'a mut self,那么您锚定该对象,在其余生中借用它,
    • 另一方面,如果您指定了新的生命周期,那么根据定义它而不是'a,并且您需要'a签名Callback

    两种情况都不奏效。

    因此,解决方案是首先避免使用寿命。

    它也更容易(在借用时)不传递self的实例,而只是传递对self.val的引用,所以我首先提出:

    type Callback = Fn(&mut i32, i32) -> i32;
    
    struct Func {
        val: i32,
        func: Option<Box<Callback>>,
    }
    
    impl Func {
        fn exec(&mut self, val: i32) -> i32 {
            if let Some(ref f) = self.func {
                return f(&mut self.val, val);
            };
            0i32
        }
    }
    
    fn main() {
        let mut a32 = Func{
            val: 10i32,
            func: Some(Box::new(|s: &mut i32, val: i32| -> i32 {
                let v = *s;
                *s += 1;
                val * 32 + v
            }))
        };
        println!("a32(4) = {}", a32.exec(4i32));
        println!("a32(4) = {}", a32.exec(4i32));
    }
    

    如果你想真正通过Func,你需要选择跳舞&#34;:

    impl Func {
        fn exec(&mut self, val: i32) -> i32 {
            let func = self.func.take();
            let res = if let Some(ref f) = func {
                f(self, val)
            } else {
                0i32
            };
            self.func = func;
            res
        }
    }
    

    请注意,self.func在回调中为空。