Rust疑问:为何借用结构体内部引用会导致整个结构体被借用?
问题分析与解答
首先看你的代码:
struct MyStruct<'a>{ data: &'a str, } fn get<'a>(S: &'a MyStruct<'a>) -> &'a str{ S.data } fn set<'a>(S: &'a mut MyStruct<'a>, x: &'a str){ S.data = x; } fn main(){ let mut S = MyStruct{data: "hello"}; let foo: &str = get(&S); set(&mut S, "goodbye"); dbg!(foo); }
为什么原代码编译失败?
你原get函数的生命周期注解把结构体的引用生命周期和结构体内部data的生命周期绑定成了同一个'a。这相当于告诉Rust:返回的&str的存活时间,和你传入的结构体引用的存活时间完全一致。
所以在main里,let foo = get(&S)这行,Rust会认为:只要foo还活着(一直到dbg!(foo)),S的不可变借用就不能被释放。而下一行set(&mut S)需要获取S的可变借用,Rust的借用规则禁止同时存在可变和不可变借用,自然就编译报错了。
修改签名后为什么能编译?
当你把get改成fn get<'a, 'b>(S: &'a MyStruct<'b>) -> &'b str时,相当于把两个生命周期解耦了:
'a是结构体引用的生命周期:这个生命周期只覆盖get函数调用的那段时间,函数执行完,结构体的不可变借用就释放了。'b是内部data的生命周期:这里data是字符串字面量,生命周期是'static,所以返回的foo可以一直活到main结束。
这样一来,get调用结束后,S的不可变借用就失效了,后面调用set获取可变借用就不会和foo的存活产生冲突,编译自然通过。
另外提一句,你原set函数的签名也有类似的生命周期绑定问题,但这次编译失败的核心原因在get的生命周期绑定逻辑。
内容的提问来源于stack exchange,提问作者jnalanko
相关产品推荐
相关产品推荐

