考虑以下测试用例:
#![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);
}
}
假设我在Handler :: find中有一些改变状态,所以我需要&mut self . 但是指向Handler内部的v_a和v_b变量都存在于自己的块中,因此这里没有借用问题 . 在这种情况下,直接为find方法指定类型参数V,并且所有内容都按预期编译 .
但后来我将参数V移动到Handler类型签名中,它停止编译“无法一次多次使用 h
可变为多次”错误:
#![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);
}
}
我真的无法理解其中的区别 . 变量v_a死后,为什么不发布可变借用?
2 回答
我认为这里发生的事情是:在您的
main
中,当您执行let mut h = Handler::<&u64>::new();
时,您的处理程序现在与该引用的生命周期相关联u64
. 因此,即使v_a
在以下块中死亡,V的生命周期必须是h
的生命周期,它仍然存在 .顺便说一句,问题不在于你已编写的代码,而是代码中你或其他人仍然可以编写 . 鉴于您使用不受约束的V定义Handler,我可以继续执行:
然后这是合法的:
因此,每当我像你一样做时,唯一安全的选择是让&64至少和h一样长 .
如果你可以使用
u64
作为V
,而不是&u64
你会没事的 . 像这样的东西会很少改变你的程序(注意我仍在使用引用,而不是通过值传递),但允许你为u32 / 64而不是&u32 / 64参数化Handler:playpen
这是我对问题的理解,其他人可能能够提供更具体的解释 .
通过将类型参数添加到结构中,您可以将该类型存储在结构中 . 由于您还指定了您的类型具有特征
Choose<'a>
and'a
与self
的生命周期相关联,因此Rust必须假定您在进行函数调用时可能会在结构中存储(可变)引用 . 然后编译器必须将您的可变借位转移到该函数,并且它不知道它何时结束 . 唯一安全的时间是对象本身超出范围这是存储
V
的示例: