Rust中的&和ref使用解讀
Rust中的&和ref使
1. & 和 ref 都是用來定義指針的
廢話少說,先看代碼:
fn main() {
let mut a: i32 = 111;
let b = &a;
println!("{}", *b); //111
let ref c = a;
println!("{}", *c); //111
}而這結果一樣,都是在聲明一個指針。區(qū)別在那里?& 放在等號的右邊, ref 放在等好的左邊。
在看個例子,看看如何用指針修改變量:
fn main() {
let mut a: i32 = 111;
let b = &mut a; // 指針 b 本身是不可以修改的,但它指向的內(nèi)容是可以修改的。
*b = 222;
println!("{}", a); // 222
let ref mut c = a; // 指針 c 本身是不可以修改的,但它指向的內(nèi)容是可以修改的。
*c = 333;
println!("{}", a); //333
}在代碼行里,二者沒有任何區(qū)別。但是,為什么弄出兩個來呢?
2. 只能用 & 定義指針的地方
看一段代碼:
fn foo(x: &mut i32) {
*x = 999;
}
fn main() {
let mut a: i32 = 111;
foo(&mut a);
println!("{}", a); // 999
}在函數(shù)傳參的時候用到了 & 來表示傳入?yún)?shù)棧的是一個可修改變量的地址。
下面我們修改一下,改成下面的代碼:
fn foo(ref mut x: i32) {
*x = 999;
}
fn main() {
let mut a: i32 = 111;
foo(a);
println!("{}", a); // 111
}foo(a) 的調(diào)用語義是說,要把 a 的值復制到棧空間,因此,fn foo(ref mut x: i32) 中參數(shù) x 引用的是棧上的數(shù)據(jù)。也就是說,不管函數(shù)的參數(shù) x 如何聲明,foo(a) 這種形式傳入?yún)?shù) a,都不可能修改變量 a 的值。我覺得這個規(guī)定是合理的,比 C++ 的引用的語義聲明簡單、合理多了。
我們再修改一下:
fn foo(ref x: &mut i32) {
**x = 999;
}
fn main() {
let mut a: i32 = 111;
foo(&mut a);
println!("{}", a); // 999
}這次又成功了。但是這個 **x 你不覺得麻煩吧?因此,在函數(shù)參數(shù)聲明中,一般只用 & 來傳入變量的地址。
3. 只能用 ref 定義指針的地方
看下面的代碼:
fn main() {
let s = Some(String::from("Hello!"));
match s {
Some(t) => println!("t = {}", t),
_ => {}
}
println!("s = {}", s.unwrap());
}這個是無法編譯的。因為 match s 語句中,已經(jīng)把 s 的所有權給轉(zhuǎn)移了,導致最后一條語句無法執(zhí)行。
編譯提示如下:

編譯期建議在模式匹配中把變量 t 改成 ref t,也就是說把 t 聲明成指針即可解決問題。
修改后代碼如下:
fn main() {
let s = Some(String::from("Hello!"));
match s {
Some(ref t) => println!("t = {}", t),
_ => {}
}
println!("s = {}", s.unwrap());
}因為在模式匹配代碼塊中,我們沒有機會聲明變量類型,只能用 ref 表示變量 t 是個指針。
我試了一下,不用 ref 的話,還有一個變通的方法,就是把 match s 改成 match &s。
代碼如下:
fn main() {
let s = Some(String::from("Hello!"));
match &s {
Some(t) => println!("t = {}", t),
_ => {}
}
println!("s = {}", s.unwrap());
}這個時候 t 前面加不加 ref 結果都一樣。因為 match 只是借用 s,所以不會影響 s 的生命周期。
4. 更多的試驗
下面給出了一組代碼,我們看看那些是合法的,那些是非法的。
fn main() {
let v = 123;
let x: &i32 = &v; // OK!
let x: &i32 = &(123 + 456); // OK!
if let Some(x:&i32) = Some(&123); // Error!
let ref x: i32 = v; // OK!
let ref x: i32 = 123 + 456; // OK!
if let Some(ref x) = Some(123) {} // OK!
}5. 指針變量的解引用
看下面代碼,道理我不多講了,rust 會自動解多層嵌套引用,這個太方便了。
fn main() {
let a: &i32 = &123;
let b: &&i32 = &a;
let c: &&&i32 = &b;
println!("a = {}, b = {}, c = {}", a, b, c);
println!("*a = {}, **b = {}, ***c = {}", *a, **b, ***c);
}
/* output
a = 123, b = 123, c = 123
*a = 123, **b = 123, ***c = 123
*/總結
以上為個人經(jīng)驗,希望能給大家一個參考,也希望大家多多支持腳本之家。
相關文章
詳解Rust調(diào)用tree-sitter支持自定義語言解析
使用Rust語言結合tree-sitter庫解析自定義語言需要定義語法、生成C解析器,并在Rust項目中集成,具體步驟包括創(chuàng)建grammar.js定義語法,使用tree-sitter-cli工具生成C解析器,以及在Rust項目中編寫代碼調(diào)用解析器,這一過程涉及到對tree-sitter的深入理解和Rust語言的應用技巧2024-09-09
C和Java沒那么香了,Serverless時代Rust即將稱王?
Serverless Computing,即”無服務器計算”,其實這一概念在剛剛提出的時候并沒有獲得太多的關注,直到2014年AWS Lambda這一里程碑式的產(chǎn)品出現(xiàn)。Serverless算是正式走進了云計算的舞臺2021-06-06
Rust重載運算符之復數(shù)四則運算的實現(xiàn)
這篇文章主要為大家詳細介紹了Rust如何實現(xiàn)復數(shù)以及復數(shù)的四則運算,文中的示例代碼講解詳細,感興趣的小伙伴可以跟隨小編一起學習一下2023-08-08
Rust語言從入門到精通系列之Iterator迭代器深入詳解
這篇文章主要為大家介紹了Rust語言從入門到精通系列之Iterator迭代器深入詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進步,早日升職加薪2023-04-04
Rust使用Channel實現(xiàn)跨線程傳遞數(shù)據(jù)
消息傳遞是一種很流行且能保證安全并發(fā)的技術,Rust也提供了一種基于消息傳遞的并發(fā)方式,在rust里使用標準庫提供的Channel來實現(xiàn),下面我們就來學習一下如何使用Channel實現(xiàn)跨線程傳遞數(shù)據(jù)吧2023-12-12

