Rust中结构体实例的定义初始化与结构体引用的语义差异
嘿,这个问题问到点子上了,刚好是Rust所有权模型里最核心的区别之一!先把你没写完的第二个代码补全(应该是漏了后半段),完整的合法写法大概是这样:
struct SomeStruct { some_field: String, } fn main() { let actual_instance = SomeStruct { some_field: "string".to_string() }; let s: &SomeStruct = &actual_instance; println!("{} ", s.some_field); }
对比第一个直接创建结构体实例的代码,两者的语义差异主要体现在这几个方面:
所有权归属完全不同
第一个代码里的s是结构体实例本身,它完全拥有这个SomeStruct的所有权——就像你买了一台电脑,这台电脑完完全全属于你,你可以随便拆改、转卖。当s离开main函数的作用域时,Rust会自动清理这个实例(包括它的String字段在堆上的数据)。
而第二个代码里的s是引用,它只是“借”了actual_instance的使用权,没有所有权——相当于你借朋友的电脑用,你只能按约定使用,不能随便改装,而且朋友随时可能把电脑拿回去。引用必须遵守Rust的借用规则:同一时间要么只能有一个可变引用,要么可以有多个不可变引用。内存布局和存在形式不一样
第一个代码的s是结构体实例本身,它的内存(结构体的元数据、字段的栈上部分)直接分配在栈上(如果字段是堆分配类型比如String,那字段的实际数据会在堆上,但结构体本身在栈)。
第二个代码的s是一个指针(64位系统下占8字节),它只存储了actual_instance的内存地址,本身不包含结构体的任何数据,只是指向真正的实例。使用权限和限制有区别
如果你把第一个代码里的s改成mut(let mut s: SomeStruct = ...),你可以直接修改它的字段:s.some_field = "new string".to_string();,完全不受限制。
但引用就不一样了:如果是不可变引用&SomeStruct,你连字段都改不了;如果是可变引用&mut SomeStruct,不仅要把原实例声明为mut,还得保证同一时间只有这一个可变引用存在,不然Rust编译器会直接报错。生命周期约束不同
引用必须始终指向“活”的实例——不能出现“悬垂引用”(比如引用指向的实例已经被销毁了)。比如如果你直接写let s: &SomeStruct = &SomeStruct { ... };,Rust会报错,因为这个临时实例在创建后马上就被销毁了,引用s就成了空指针。而拥有所有权的实例只要自己在作用域内,就始终是有效的,不用担心这个问题。
简单来说,一个是“拥有实物”,一个是“拿了个钥匙去开别人的门”——这就是Rust里结构体实例和引用最本质的语义差异。
备注:内容来源于stack exchange,提问作者mrn

