理解Rust的引用與借用


https://www.jianshu.com/p/ac519d8c5ec9

困惑

接觸Rust也一段時間了,但對References(引用) 、borrowing(借用) 、 &關鍵字、ref關鍵字、* 關鍵字,這幾個詞非常困惑。常見的問題不在乎下面幾條:

  1. &關鍵字是代表引用還是借用?
  2. ref 和 & 有什么區別?
  3. 總是與c++的引用對比,他們意思相同?(因為人在學習中總與現有的知識對比,所以有了這一條)

網上有很多對Rust中引用和借用部分進行翻譯和解釋。看得真是雲里霧里,一會說借用,一會說引用,那到底是引用還是借用?

現象

rust中借用和引用的附帶功效都一樣,就是都有生命周期。借用使用&關鍵字,引用使用ref關鍵字。借用的對象是必須存在的,引用的對象可以虛擬的,后期附上對象。

我看這網上的一段解釋,Rust的引用和c++ 語言的引用完全不一樣啊,c++ 語言說的是,引用類似變量別名,聲明引用時,必須同時對其進行初始化。

引用的聲明方法:類型標識符 &引用名=目標變量名

再看下出自《Programming Rust Fast, Safe Systems Development》

in Rust terminology, we say that it borrows a reference to x. Given a
reference r, the expression *r refers to the value r points to. These are very much like
the & and * operators in C and C++
Unlike C pointers, however, Rust references are never null: there is simply no way to
produce a null reference in safe Rust. And Rust references are immutable by default:

這怎么拿Rust引用與C++的指針進行比較了。都不知道那種是更合理的解釋。

實踐

實踐出真知,還是動動手。

  • 首先證明的是引用是否可以為空。
let ref a:i32; //a = 1; // expected &i32,consider borrowing here: `&1` a = &1; 

上面代碼能編譯通過,這說明Rust中的引用和c++ 中的引用不是一個意思,更像c++ 中的指針類型。c++ 通過int *a來聲明指針類型。

  • ref 與 & 的區別
let ref a=2; let a = &2; 

兩個值都是&i32類型。

所以ref用在變量綁定與&用在表達式上是一樣的效果。
看到上一個例子的錯誤提示,consider borrowing here,那么&在Rust的表達式上可以看成是借用,這與c++ 取地址符是一個意思。

struct B<'l> { pub a: &'l u32, // pub b: ref u32, expected type, found keyword `ref` } let ref a = &1; let b = B{ a: a }; 

在類型聲明上,&表示引用類型。

  • & 與 * 的關系

那么&用在綁定上是怎么樣的?其實&用在綁定上與*用在表達式上是一樣的:

let r=&1;
let &a=r;
let a=*r;

兩個值都是i32類型。

如果上面的解釋還沒有讓你明白他們之間的關系,那么通過代碼直接輸出具體類型,這能加深理解。

#![feature(core_intrinsics)] fn main() { let x = &false; print_type_name_of(x); let &x = &false; print_type_name_of(x); let ref x = &false; print_type_name_of(x); } fn print_type_name_of<T>(_: T) { println!("{}", unsafe { std::intrinsics::type_name::<T>() }) } 
&bool bool &&bool 

例子:

#![feature(core_intrinsics)] enum Favour<'a> { Nor(u32), NorRef(u32), Ref(&'a u32), RefRef(&'a u32), } fn config(data: &u32) { println!("log data: {}", data); } // fn con(data: ref u32){ //expected type, found keyword `ref` // println!("log data: {}", data); // } fn log(fav: Favour) { match fav { Favour::Nor(data) => { config(&data); print_type_name_of(data); }, Favour::NorRef(ref data) => { config(data); print_type_name_of(data); }, Favour::Ref(data) => { config(data); print_type_name_of(data); }, Favour::RefRef(ref data) => { config(data); print_type_name_of(data); } } } fn print_type_name_of<T>(_: T) { println!("{}", unsafe { std::intrinsics::type_name::<T>() }) } fn main() { log(Favour::Nor(1)); log(Favour::Ref(&2)); log(Favour::NorRef(3)); log(Favour::RefRef(&4)); } 
log data: 1
u32
log data: 2
&u32
log data: 3
&u32
log data: 4
&&u32

match的模式匹配上只能使用 ref,在函數聲明上只能使用&來表示引用類型

總結

單純Rust語言上考慮。
我們在不同情況下解釋&的意思:

  1. 在表達式上,表示的是借用。
  2. 在變量綁定上,表示解地址操作與*類似。
  3. 在類型聲明上,表示引用類型。
  4. 在模式匹配上,無效關鍵字

那么ref的通用解釋是:

  1. 在表達式上,無效關鍵字
  2. 在變量綁定上,表示引用類型。
  3. 在類型聲明上,無效關鍵字
  4. 在模式匹配上,表示引用類型。

非要給區分ref&到底哪個是引用,哪個是借用。我們可以先從詞性划分,引用我歸類為名詞,而借用歸類為動詞。&A在表達式上 表示借用A,這是一個動作,那結果就是產出一個引用類型。所以let ref B表示聲明了一個引用類型,它只能綁定到某次借用動作上。

所以ref 更適合叫引用, &叫借用。

參考:

when-to-ref-or
ref-keyword-versus
rust-by-example



作者:kayryu
鏈接:https://www.jianshu.com/p/ac519d8c5ec9
來源:簡書
著作權歸作者所有。商業轉載請聯系作者獲得授權,非商業轉載請注明出處。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM