目录


一,Clone、Copy
1,基本类型
rust基本类型包括:
- 所有整数类型,比如
u32 - 布尔类型,
bool,它的值是true和false - 所有浮点数类型,比如
f64 - 字符类型,
char
2,类型的Clone特征
拥有Clone特征的类型:
- 基本类型
- String
- 容器
- 显式声明Clone特征的结构体
没有Clone特征的类型:
- 没有显式声明Clone特征的结构体(结构体默认)
递归决定是否有Clone特征的类型:
- 元组,当且仅当其包含的类型都有Clone特征的情况下,其自身有Clone特征。
3,显式声明结构体的Clone特征
显式声明结构体的Clone特征的前提条件:当且仅当结构体中的成员都具有Clone特征的情况下,可以显式声明Clone特征。
#[derive(Clone)]
struct S{}
#[derive(Clone)]
struct P{
a:i32,
b:S,
}
4,类型的Copy特征
拥有Copy特征的类型:
- 基本类型
- 显式声明Copy特征的结构体
没有Copy特征的类型:
- String
- 容器
- 没有显式声明Copy特征的结构体(结构体默认)
递归决定是否有Copy特征的类型:
- 元组,当且仅当其包含的类型都有Copy特征的情况下,其自身有Copy特征。
5,显式声明结构体的Copy特征
一定是具有Clone特征的类型,才可能具有Copy:
pub trait Copy: Clone {
// Empty.
}
显式声明结构体的Copy特征的前提条件:当且仅当结构体中的成员都具有Copy特征的情况下,可以显式声明Copy特征。
#[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,转移的永久性
错误代码:
fn f(){
let x = "he".to_string();
if false{
let y = x;
}
println!("{}",x);
}
错误原因:y转移了x的所有权之后,x就再也不能用了,即使y的生命周期结束了也一样。
即使这里用if false包起来了,只要这部分代码能编译,y就转移走x的所有权。
5,赋值语句
无论是let语句,还是赋值语句,有Copy的就会Copy,没有Copy的就转移所有权。
PS:等号右边是形如x.clone()的,虽然不会转移x本身的所有权,但是会转移走clone函数返回值的所有权。
struct S{
x:i32
}
fn main() {
let c= S{x:1};
let mut d =S{x:2};
d=c;
assert_eq!(d.x, 1);
let mut x = Vec::from([1,2,3]);
let mut y = Vec::from([1,2,4]);
y=x;
assert_eq!(y[2], 3);
let x = 5;
let mut y = 6;
y=x;
assert_eq!(x, 5);
assert_eq!(y, 5);
}
三,引用、Borrow
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;
if false{
assert_eq!(y.a,5);
}
println!("end");
}
错误原因:在y的读行为结束之前,x不能执行写行为,否则会造成冲突。即使后面的y的读写包在了if false里面也是一样,因为编译器不做这种代码运行推导。
同一个变量可以引用多次,也可以对引用变量再进行引用:
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不能执行读行为,否则会造成冲突。
可变引用和不可变引用不能同时存在,否则会造成冲突。
4,函数调用
错误代码:
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");
}
实现方式:函数入参改成引用类型,传参时也要改成引用。
5,Borrow、BorrowMut
泛型的Borrow特征比单纯的引用更加强大,比如可以引用数据内的部分数据,或者和指针相关的操作。
pub trait Borrow<Borrowed: ?Sized> {
#[stable(feature = "rust1", since = "1.0.0")]
fn borrow(&self) -> &Borrowed;
}
pub trait BorrowMut<Borrowed: ?Sized>: Borrow<Borrowed> {
#[sta
Rust语言Clone、指针等特性详解

该博客围绕Rust语言展开,详细介绍了Clone、Copy特征,变量绑定与赋值的不同场景,引用和Borrow的使用规则及生命周期。还深入剖析了多种智能指针,如NonNull、UnsafeCell等的含义、用法和源码,以及指针的搭配使用和分类,最后提及了ref的相关内容。
最低0.47元/天 解锁文章
545

被折叠的 条评论
为什么被折叠?



