Consider the following test case: #![allow(unstable)]trait Choose<'o> { fn choose(a: &'o u64, b: &'o u32) -> Self;}impl<'o> Choose<'o> for &'o u64 { fn choose(a: &'o u64, _b: &'o u32) -> &'o u64 { a }}impl<'o> Choose<'o> for &'o u32 { fn choose(_a: &'o u64, b: &'o u32) -> &'o u32 { b }} // 'struct Handler { a: u64, b: u32,}impl Handler { fn new() -> Handler { Handler { a: 14, b: 15 } } fn find<'a, V, W>(&'a mut self, value: W) -> Option<V> where V: Choose<'a>, W: PartialEq<V> { // ' let v = Choose::choose(&self.a, &self.b); if value == v { Some(v) } else { None } }}fn main() { let mut h = Handler::new(); { let v_a = h.find::<&u64, &u64>(&14u64); println!("v_a = {:?}", v_a); } { let v_b = h.find::<&u64, &u64>(&15u64); println!("v_b = {:?}", v_b); }}playpenSuppose I have some changing state inside Handler::find, so I need &mut self. But both v_a and v_b variables pointing to Handler internals live inside their own blocks, so there is no borrow problems here. In this case a type parameter V is specified for a find method directly, and everything compiles as expected.But then I move parameter V into Handler type signature and it stops compiling with "cannot borrow h as mutable more than once at a time" error: #![allow(unstable)]trait Choose<'o> { fn choose(a: &'o u64, b: &'o u32) -> Self;}impl<'o> Choose<'o> for &'o u64 { fn choose(a: &'o u64, _b: &'o u32) -> &'o u64 { a }}impl<'o> Choose<'o> for &'o u32 { fn choose(_a: &'o u64, b: &'o u32) -> &'o u32 { b }} // 'struct Handler<V> { a: u64, b: u32,}impl<V> Handler<V> { fn new() -> Handler<V> { Handler { a: 14, b: 15 } } fn find<'a, W>(&'a mut self, value: W) -> Option<V> where V: Choose<'a>, W: PartialEq<V> { // ' let v = Choose::choose(&self.a, &self.b); if value == v { Some(v) } else { None } }}fn main() { let mut h = Handler::<&u64>::new(); { let v_a = h.find(&14u64); println!("v_a = {:?}", v_a); } { let v_b = h.find(&15u64); println!("v_b = {:?}", v_b); }}playpenI really cannot understand the difference. Why mutable borrow is not released after variable v_a is dead? 解决方案 I think what is happening here is:in your main, when you do let mut h = Handler::<&u64>::new();, your Handler is now tied to the lifetime of that reference to u64.So even if v_a dies in the following block, the lifetime of V must be that of h, which is still alive.The problem, by the way, is not so much in the code you already wrote, but in the code you or somebody else could still write.Given your definition of Handler with an unconstrained V, I could go ahead and do:// in the meanwhile, in another crate...// I create another traittrait MyTrait { fn foo(&self) -> &u64;}// and implement it for Handler<&u64>impl<'a> MyTrait for Handler<&'a u64> { fn foo(&self) -> &u64 { &self.a }}and then this would be legal:let h = Handler::<&u64>::new();println!("{}", h.foo()); // prints 14So, whenever I do let h = Handler::<&u64>::new(); like you did, the only safe option is for the &64 to live at least as long as h.If you could use u64 as V, instead of &u64 you would be fine. Something like this changes your program very little (note that I'm still working with references, not passing by value), but allows you to parametrize Handler for u32/64 instead of &u32/64 :trait Choose<'o> { fn choose(a: &'o u64, b: &'o u32) -> &'o Self;}impl<'o> Choose<'o> for u64 { fn choose(a: &'o u64, _b: &'o u32) -> &'o u64 { a }}impl<'o> Choose<'o> for u32 { fn choose(_a: &'o u64, b: &'o u32) -> &'o u32 { b }}struct Handler<V> { a: u64, b: u32,}impl<V> Handler<V> { fn new() -> Handler<V> { Handler { a: 14, b: 15 } } fn find<'a, W>(&'a mut self, value: W) -> Option<&'a V> where V: Choose<'a>, W: PartialEq<&'a V> { let v = Choose::choose(&self.a, &self.b); if value == v { Some(v) } else { None } }}fn main() { let mut h = Handler::<u64>::new(); { let v_a = h.find(&14u64); println!("v_a = {:?}", v_a); } { let v_b = h.find(&15u64); println!("v_b = {:?}", v_b); }}playpen 这篇关于函数vs结构的类型参数(生命周期问题)的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!
09-09 16:32