Rust中的引用類型
本節簡單介紹Rust中的引用,混個臉熟,後面會專門詳細介紹引用以及引用更細節更底層的內容。
Rust中,使用&T
表示類型T的引用類型(reference type)。
例如,&String
表示String的引用類型,&i32
表示i32的引用類型,&&i32
表示i32引用的引用類型。
引用類型是一種數據類型,它表示其所保存的值是一個引用。
值的引用寫法和引用類型的寫法類似。例如&33
表示的是33這個值的引用。
引用,通常來說是指向其他數據的一個指針或一個胖指針(有額外元數據的指針)。例如&33
表示的是一個指向數據值33的一個指針。
因此,引用類型保存值的引用。
例如:
#![allow(unused)] fn main() { let n: &i32 = &33_i32; }
這裡變量n的類型是引用類型&i32
,它所保存的值必須是i32類型數據的引用,例如上面的&33_i32
就是33_i32
的引用。
可以將保存了引用的變量賦值給其他變量,這樣就有多個變量擁有同一份數據的引用。
fn main(){ let n = 33; let n_ref1 = &n; // n_ref1指向33 let n_ref2 = n_ref1; // n_ref2也指向33 }
可以使用std::ptr::eq()
來判斷兩個引用是否指向同一個地址,即判斷所指向的數據是否是同一份數據。
fn main(){ let n = 33; let n_ref1 = &n; let n_ref2 = n_ref1; println!("{}", std::ptr::eq(n_ref1, n_ref2)); // true }
可變引用
直接使用&
創建出來的引用是隻讀的,這意味著可以通過該引用去讀取其指向的數據,但是不能通過引用去修改指向的數據。
如果想要通過引用去修改源數據,需要使用&mut v
來創建可修改源數據v的可變引用。
注意,想要通過&mut
引用去修改源數據,要求原變量是可變的。這很容易理解,&mut
是一個對源數據的引用,如果源數據本身就不允許修改,當然也無法通過&mut
去修改這份數據。
因此,使用&mut
的步驟大致如下:
#![allow(unused)] fn main() { let mut x = xxxx; let x_ref = &mut x; }
例如,下面聲明的變量n是不可變的,即使創建&mut n
,也無法修改原始數據。實際上,這會導致編譯錯誤。
fn main(){ let n = 33; let n_ref = &mut n; // 編譯錯誤 }
因此,改為如下代碼可編譯通過:
fn main(){ let mut n = 33; let n_ref = &mut n; }
解引用
解引用表示解除引用,即通過引用獲取到該引用所指向的原始值。
解引用使用*T
表示,其中T是一個引用(如&i32
)。
例如:
fn main(){ let s = String::from("junma"); let s_ref = &s; // s_ref是指向"junma"的一個引用 // *s_ref表示通過引用s_ref獲取其指向的"junma" // 因此s和*s_ref都指向同一個"junma",它們是同一個東西 assert_eq!(s, *s_ref); // true }
再例如:
fn main(){ let mut n = 33; let n_ref = &mut n; n = *n_ref + 1; println!("{}", n); }
Rust絕大多數時候不會自動地解除引用。但在某些環境下,Rust會自動進行解引用。
自動解引用的情況有(結論先總結在此,混臉熟,以後涉及到時再來):
- (1).使用
.
操作符時(包括取屬性值和方法調用),會隱式地儘可能解除或創建多層引用 - (2).使用比較操作符時,若比較的兩邊是相同類型的引用,則會自動解除引用到它們的值然後比較
對於(1),Rust會自動分析func()的參數,並在需要的時候自動創建或自動解除引用。例如以abc.func()
有可能會自動轉換為&abc.func()
,反之,&abc.func()
也有可能會自動轉換為abc.func()
。
對於(2),例如有引用類型的變量n,那麼n > &30
和*n > 30
的效果是一樣的。