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 -------+