rust变量绑定、拷贝、转移、引用
- 开源代码
- 2025-08-13 11:18:02

目录
一,clone、copy
1,基本类型
2,类型的clone特征
3,显式声明结构体的clone特征
4,类型的copy特征
5,显式声明结构体的clone特征
5,变量和字面量的特征
6,特征总结
二,变量绑定
1,clone拷贝场景
2,copy拷贝场景
3,所有权转移场景
4,转移的永久性
三,引用
1,对常量的引用
2,对变量的不可变引用
3,对变量的可变引用
5,函数调用
四,引用总结
1,引用的生命周期
2,对字面量的引用
3,对普通变量的引用
4,对引用变量的引用
5,对同一变量的引用
6,链式引用
一,clone、copy 1,基本类型
rust基本类型包括:
所有整数类型,比如 u32布尔类型,bool,它的值是 true 和 false所有浮点数类型,比如 f64字符类型,char 2,类型的clone特征拥有clone特征的类型:
基本类型String容器显式声明clone特征的结构体没有clone特征的类型:
没有显式声明clone特征的结构体(结构体默认)递归决定是否有clone特征的类型:
元组,当且仅当其包含的类型都有clone特征的情况下,其自身有clone特征。 3,显式声明结构体的clone特征前提条件:当且仅当结构体中的成员都具有clone特征的情况下,可以显式声明clone特征。
#[derive(Clone)] struct S{} #[derive(Clone)] struct P{ a:i32, b:S, } 4,类型的copy特征拥有copy特征的类型:
基本类型显式声明clone特征的结构体没有copy特征的类型:
String容器没有显式声明clone特征的结构体(结构体默认)递归决定是否有copy特征的类型:
元组,当且仅当其包含的类型都有copy特征的情况下,其自身有copy特征。 5,显式声明结构体的clone特征前提条件:结构体具有clone特征
#[derive(Clone,Copy)] struct P{ a:i32, } fn main() { let x:P=P{a:5}; let y=x; assert_eq!(x.a,5); } 5,变量和字面量的特征字面量会自动推导出类型,所以变量和字面量都有唯一确定的类型。
变量和字面量是否具有clone和copy特征,完全取决于其类型是否具有。
6,特征总结所有类型可以分为3类:
没有clone和copy特征,有clone没有copy特征,有clone和copy特征。
二,变量绑定 1,clone拷贝场景对于有clone特征的变量或字面量,可以调用clone函数进行拷贝而不转移所有权。
#[derive(Clone)] struct P{ a:i32, } fn main() { let x:P=P{a:5}; let y=x.clone(); assert_eq!(x.a,5); } 2,copy拷贝场景如果let绑定语句的等号右边是一个有copy特征的变量或字面量,那么这是一个拷贝行为。
let x = 5; let xx = x; assert_eq!(5, x); assert_eq!(6, xx+1); 3,所有权转移场景如果let绑定语句的等号右边是一个没有copy特征的变量或字面量,那么这是一个所有权转移的行为。
错误代码:
let x = vec![1,2,3]; assert_eq!(x[0],1); let y=x; assert_eq!(x[0],1); // 错误错误原因:y转移走了所有权,不能再使用x
4,转移的永久性错误代码:
struct P{ a:i32, } fn main() { let mut x:P=P{a:5}; { let y= x; } x.a=6; println!("end"); }错误原因:y转移了x的所有权之后,x就再也不能用了,即使y的生命周期结束了也一样。
三,引用 1,对常量的引用 fn main() { let x:P=P{a:6}; let y= & x; assert_eq!(x.a,6); assert_eq!(y.a,6); assert_eq!((*y).a,6); println!("end"); }常量只有可读性,原变量x和引用变量y都持有读的能力。
这里y可以直接用,也可以先解引用再用。
2,对变量的不可变引用正确代码:
struct P{ a:i32, } fn main() { let mut x:P=P{a:6}; let y= &x; assert_eq!(x.a,6); assert_eq!(y.a,6); assert_eq!((*y).a,6); x.a=5; assert_eq!(x.a,5); println!("end"); }变量x持有读写能力,不可变的引用y只有读能力。
错误代码:
struct P{ a:i32, } fn main() { let mut x:P=P{a:6}; let y= &x; x.a=5; assert_eq!(y.a,5); println!("end"); }错误原因:在y的读行为结束之前,x不能执行写行为,否则会造成冲突。
同一个变量可以引用多次,也可以对引用变量再进行引用:
struct P{ a:i32, } fn main() { let mut x:P=P{a:6}; let y= &x; let z=&x; let z2=&z; let z3=&z2; let z4=&z3; assert_eq!(x.a,6); assert_eq!(y.a,6); assert_eq!(z.a,6); assert_eq!(z4.a,6); assert_eq!((*z4).a,6); assert_eq!((**z4).a,6); assert_eq!((***z4).a,6); assert_eq!((****z4).a,6); println!("end"); }这里的z4可以直接读成员,也可以解引用若干次再使用。
3,对变量的可变引用正确代码:
struct P{ a:i32, } fn main() { let mut x:P=P{a:6}; let y= &mut x; assert_eq!(y.a,6); y.a=5; assert_eq!(x.a,5); println!("end"); }错误代码:
struct P{ a:i32, } fn main() { let mut x:P=P{a:6}; let y= &mut x; assert_eq!(x.a,6); assert_eq!(y.a,6); println!("end"); }错误原因:y的读写行为结束之前,x不能执行读行为,否则会造成冲突。
可变引用和不可变引用不能同时存在,否则会造成冲突。
5,函数调用错误代码:
fn fun(x:Vec<i32>)->i32{ x[0]+1 } fn main() { let x = vec![1,2,3]; assert_eq!(fun(x),2); assert_eq!(x.len(), 3); println!("end"); }错误原因:函数调用时转移走了所有权。
正确代码:
fn fun(x:&Vec<i32>)->i32{ x[0]+1 } fn main() { let x = vec![1,2,3]; assert_eq!(fun(&x),2); assert_eq!(x.len(), 3); println!("end"); }实现方式:函数入参改成引用类型,传参时也要改成引用。
四,引用总结 1,引用的生命周期(1)一个引用变量的声明周期只到它的最后一次读写为止
(2)如果声明了引用之后没有读写,那么生命周期直接结束,但是这和直接删除这一句不一样,因为声明引用这一行相当于一次读操作。
(3)如果一个引用变量y被z引用了,且z最后一次读写比y的最后一次读写更晚,那么y的生命周期延长到z的最后一次读写。
PS:如果声明了z是对y的引用之后没有读写,那么声明的这一句就是z的最后一次读操作,这也可能延长y的声明周期。
讨论引用规则时我们默认只讨论一个生命周期之内的引用。
2,对字面量的引用对字面量的引用,无论是可变引用还有不可变引用,其实都不是引用,而是copy拷贝,讨论引用规则时我们默认不把对字面量的引用这个当做引用。
3,对普通变量的引用对于普通变量,有mut的是可变变量,没有mut的是不可变变量(常量)。
可变变量可以加可变引用,也可以加不可变引用,不可变变量只能加不可变引用。
4,对引用变量的引用无论是可变引用变量还是不可变引用变量,都和普通变量一样,可能是可变变量也可能是不可能变量。
对引用变量加引用的规则,和对普通变量一致。
5,对同一变量的引用对不可变变量不能加可变引用,可以加多个不可变引用。
对可变变量可以加唯一的可变引用,也可以加多个不可变引用。
即,可变引用存在的情况下,只能有一个引用。
6,链式引用以y是对x的引用,z是对y的引用为例,更长的链的情况应该规则类似。
y的声明周期参考上文“引用的生命周期”。
在所有情况下,z对x的读写能力都和y对x的读写能力相同,因为z一直持有对y的读能力。
(1)x是不可变变量
x和y 一直有读能力,没有写能力
(2)x是可变变量
在y的最后一次读操作或写操作之前,x没有读写能力,之后,x有读写能力
y的能力在声明周期内不变,有读能力,有没有写能力取决于是可变引用还是不可变引用。
五,ref当我们要引用一个Option的内部成员,可以用ref
struct P{ a:i32, } struct Node{ x:Option<P>, } fn main() { let mut p = Node{x:Some(P{a:1})}; if let Some(ref mut x)=p.x{ x.a=2; } if let Some( x)=p.x{ assert_eq!(x.a,2); } println!("end"); }rust变量绑定、拷贝、转移、引用由讯客互联开源代码栏目发布,感谢您对讯客互联的认可,以及对我们原创作品以及文章的青睐,非常欢迎各位朋友分享到个人网站或者朋友圈,但转载请说明文章出处“rust变量绑定、拷贝、转移、引用”