最近學習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中沒有失效的屬性。