最近学习rust,网上资料还是很有限,做题遇到的问题,有时需要自己试验。把自己做题过程遇到的问题,和试验的结论,做一些简单记录。
阅读下列文字和代码
用切片(的引用)做参数要非常小心,切片中的某个元素直接用=赋值,用的是copy方式而不是所有权转移(实践证明)。
如果要用切片中的值赋值,那么可以对切片元素clone(需要元素类型实现Clone trait),
或者限制切片元素类型为实现了copy trait。String没有实现Copytrait,实现了Clone trait
let l: String = *y;(y是&String),这种解引用再用=赋值,走的也是copy方式,
就会报错(String没实现copy trait)
给类型上加#[derive(Copy)]可以添加Copy特征,Copy特征有自己默认实现的代码,
这个类型就可以调用它们,也可以自己重写方法
fn main() {
let mut x = String::from("hello");
let y = &x;
let z = y;
println!("{}", *y);
// let l: String = *y; // 会报错。通过报错信息可知,解引用再用=赋值,是copy操作
// 直接将String本身用=赋值,是转移所有权;
// 将String本身的引用,解引用后用=赋值,是copy操作,
// String没有实现copy特性,所以会报错(上一行)
let l = x;
}
fn largest2(s: &[String]) -> String {
// 下面错误,原因是会发生所有权转移,但是s是一个切片(的引用),
// 切片:[String, String, ... , String],
// 如果其中某个元素发生了所有权转移,是不被允许的,所以这里只能通过拷贝
// 但是String没有实现copy trait,所以会报错。正确做法是用clone()
// let mut res: String = s[0];
let mut res: String = s[0].clone();
res
}
/*
重大发现,这个泛型如果不限制它实现copy特征,那么发生传值的时候,
比如我写let x = list[0],注意list是这个切片首地址,list[0]就是切片中首元素,
它是T类型的,这种赋值方式会copy一份给x绑定,如果T没实现copy trait怎么办?
所以要限定T的范围,这里限定T为实现了Copy特征的类型
*/
fn largest<T: std::cmp::PartialOrd + Copy>(list: &[T]) -> T {
let mut res = &list[0];
for i in list.iter() {
if *i > *res {
res = i;
}
}
*res // res是T类型的引用,这种返回是用&T
}
// 如果要用clone(),得确保类型实现了Clone
fn largest1<T: std::cmp::PartialOrd + Clone>(list: &[T]) -> T {
let mut res = list[0].clone();
for i in list.clone() {
if *i > res {
res = i.clone();
}
}
res
}
结构体赋值的例子
这个是从rust圣经上摘录的
struct User {
active: bool,
username: String,
email: String,
sign_in_count: u64,
}
我们创建了一个user1,代码略,然后用user1更新user2:
let user2 = User {
email: String::from("another@example.com"),
..user1
};
这里除了email是新创建,其他都是和user1一样。其中username字段进行了所有权转移,原因:
实现了 Copy 特征的类型无需所有权转移,可以直接在赋值时进行 数据拷贝,其中 bool 和 u64 类型就实现了 Copy 特征(来源rust圣经)
由于user1中username的所有权转移给了user2,user1之后就不能使用了。但是通过user1.active、user1.email、user1.sign_in_count可以使用user1中没有失效的属性。