Rust 此错误是由编译器';什么是关于RefCell的专门知识? fn工作,s:&'a mut String){ fn错误>,s:&'a mut字符串){} 让mut s=“hi”。to_string(); 设foo=None; 工程(foo和mut s); //有了这个,它就错了 //让bar=RefCell::new(无); //错误(&bar,&mut s); s、 len();
如果我将注释放在两行中,则会出现以下错误:Rust 此错误是由编译器';什么是关于RefCell的专门知识? fn工作,s:&'a mut String){ fn错误>,s:&'a mut字符串){} 让mut s=“hi”。to_string(); 设foo=None; 工程(foo和mut s); //有了这个,它就错了 //让bar=RefCell::new(无); //错误(&bar,&mut s); s、 len();,rust,borrow-checker,Rust,Borrow Checker,如果我将注释放在两行中,则会出现以下错误: error[E0502]:无法将's'作为不可变项借用,因为它也是作为可变项借用的 --> :16:5 | 14 |错误(&bar,&mut s); |-此处发生可变借用 15 | 16 | s.len(); |^此处发生不可变借用 17 | } |-可变借用结束于此 works()和errors()的签名看起来非常相似。但显然,编译器知道可以使用RefCell对其进行欺骗,因为借用检查器的行为不同 我甚至可以将RefCell隐藏在我自己的
error[E0502]:无法将's'作为不可变项借用,因为它也是作为可变项借用的
--> :16:5
|
14 |错误(&bar,&mut s);
|-此处发生可变借用
15 |
16 | s.len();
|^此处发生不可变借用
17 | }
|-可变借用结束于此
works()
和errors()
的签名看起来非常相似。但显然,编译器知道可以使用RefCell
对其进行欺骗,因为借用检查器的行为不同
我甚至可以将RefCell
隐藏在我自己的另一种类型中,但编译器仍然总是做正确的事情(如果可以使用RefCell
,则会出现错误)。编译器是如何知道所有这些东西的?它是如何工作的?编译器是否将类型标记为“内部可变容器”或类似的内容?RefCell
包含一个特殊的。导致错误的是UnsafeCell
。您可以通过以下方式进行检查:
fn works<'a>(foo: &Option<&'a mut String>, s: &'a mut String) {}
fn error<'a>(foo: &RefCell<Option<&'a mut String>>, s: &'a mut String) {}
let mut s = "hi".to_string();
let foo = None;
works(&foo, &mut s);
// with this, it errors
// let bar = RefCell::new(None);
// error(&bar, &mut s);
s.len();
甚至是任何在生命周期中是逆变的或不变的东西'a
:
struct Contravariant<T>(PhantomData<fn(T)>);
fn error<'a>(foo: Contravariant<&'a i32>, s: &'a mut String) {}
...
let bar = Contravariant(PhantomData);
error(bar, &mut s);
在逆变和不变情况下,'a
超过(或等于)'x
表示语句s.len()
必须包含在范围内,从而导致借用错误
只有在协变情况下,我们才能使'a
的范围小于'x
,允许在调用s.len()
之前删除临时对象&mut s
(意思是:在s.len()
,不再认为s
):
let bar=协变(幻影数据);//天哪!多么惊人的回答!我已经担心答案会是“RefCell
is special”,但这是一个惊人的见解。谢谢♥ 但是有一个问题:在foo中:Option@LukasKalbertodt如果是额外的解释,而不是问题,请随意。(如果评论框太小是其他相关问题,请改为编辑问题)。@LukasKalbertodt我相信选项
struct Contravariant<T>(PhantomData<fn(T)>);
fn error<'a>(foo: Contravariant<&'a i32>, s: &'a mut String) {}
...
let bar = Contravariant(PhantomData);
error(bar, &mut s);
fn error<'a>(foo: Option<fn(&'a i32)>, s: &'a mut String) {}
let bar = None;
error(bar, &mut s);
let bar = Contravariant(PhantomData); // <--- 'x starts here -----+
error(bar, // |
&mut s); // <- 'a starts here ---+ |
s.len(); // | |
// <--- 'x ends here¹ --+---+
// |
// <--- 'a ends here² --+
}
// ¹ when `bar` goes out of scope
// ² 'a has to outlive 'x
let bar = Covariant(PhantomData); // <--- 'x starts here -----+
// |
error(bar, // |
&mut s); // <- 'a starts here --+ |
// | |
// <- 'a ends here ----+ |
s.len(); // |
} // <--- 'x ends here -------+