Rust中的方法與關(guān)聯(lián)函數(shù)使用解讀
1. 方法(Methods)是什么?
在 Rust 里,方法和函數(shù)的定義方式很像:
- 都使用
fn
來(lái)聲明。 - 都能擁有參數(shù)和返回值。
- 都包含一段在被調(diào)用時(shí)執(zhí)行的代碼邏輯。
不同點(diǎn)在于: 方法必須定義在某個(gè)具體類型(比如 struct
、enum
或者在某個(gè) trait 對(duì)象里)的上下文中。而且方法的第一個(gè)參數(shù)固定要寫(xiě)成 self
(可以是 self
、&self
或者 &mut self
),用來(lái)代表調(diào)用該方法的具體實(shí)例。
讓我們來(lái)看看一個(gè)簡(jiǎn)單示例。假設(shè)我們有一個(gè) Rectangle
結(jié)構(gòu)體:
#[derive(Debug)] struct Rectangle { width: u32, height: u32, }
如果你想為 Rectangle
實(shí)例添加一個(gè)計(jì)算面積的功能,我們可以在 impl
(implementation)塊中為它定義一個(gè)方法 area
:
impl Rectangle { fn area(&self) -> u32 { self.width * self.height } }
- 這里
impl Rectangle { ... }
表示這個(gè)塊里的所有函數(shù)都與Rectangle
類型相關(guān)聯(lián)。 fn area(&self) -> u32
說(shuō)明:這是一個(gè)方法,第一個(gè)參數(shù)是&self
,表示以不可變引用的形式訪問(wèn)當(dāng)前調(diào)用該方法的Rectangle
實(shí)例。self.width
和self.height
即代表該實(shí)例的字段。用self
訪問(wèn)字段非常直觀。
在 main
函數(shù)中,當(dāng)我們創(chuàng)建一個(gè)矩形實(shí)例后,就可以使用方法語(yǔ)法來(lái)獲取面積:
fn main() { let rect1 = Rectangle { width: 30, height: 50, }; println!("rect1 的面積是:{}", rect1.area()); }
運(yùn)行后,會(huì)輸出:
rect1 的面積是:1500
2. 為什么要使用 &self 而不是 &Rectangle?
在我們將 area
從一個(gè)普通函數(shù)重構(gòu)為一個(gè)方法時(shí),你會(huì)注意到,函數(shù)簽名由原本的
fn area(rectangle: &Rectangle) -> u32 { ... }
變?yōu)?/p>
fn area(&self) -> u32 { ... }
這是因?yàn)樵?impl Rectangle
這個(gè)上下文中,Rust 給出了一個(gè)更具可讀性的方式:讓第一個(gè)參數(shù)自動(dòng)變?yōu)?self
,而 Self
則是當(dāng)前實(shí)現(xiàn)塊對(duì)應(yīng)的類型別名。
如果你需要修改實(shí)例的字段,你可以將第一個(gè)參數(shù)寫(xiě)為 &mut self
;如果需要獲取所有權(quán)并可能在方法內(nèi)部把它“轉(zhuǎn)化”成別的東西,則用 self
。但這種把所有權(quán)轉(zhuǎn)移給方法本身的做法很少見(jiàn)。
在大多數(shù)情況下,我們只是想讀一下結(jié)構(gòu)體數(shù)據(jù)而不改變它,這時(shí)使用 &self
最為常見(jiàn),也能讓調(diào)用者繼續(xù)使用這個(gè)實(shí)例。
3. 同名字段與同名方法
如果你在 Rectangle
內(nèi)也有一個(gè)字段叫做 width
,同時(shí)還想定義一個(gè)方法也叫 width
,這是合法的。比如:
impl Rectangle { fn width(&self) -> bool { self.width > 0 } }
在調(diào)用時(shí):
rect.width
(不帶括號(hào))訪問(wèn)的是字段width
的數(shù)值。rect.width()
(帶括號(hào))調(diào)用的是同名方法,返回一個(gè)布爾值。
在很多語(yǔ)言中,如果你只想單純地返回字段值,會(huì)把這種方法稱為“getter”。
Rust 并不會(huì)為你自動(dòng)生成 getter,但你可以自行定義。
這樣一來(lái),你可以只把字段設(shè)為私有,但對(duì)外公開(kāi)這個(gè)只讀方法,讓外部安全地訪問(wèn)它。
4. 借用與解引用:為什么在調(diào)用方法時(shí)不需要寫(xiě) & 或 *?
在 C/C++ 中,如果你要通過(guò)指針來(lái)調(diào)用成員函數(shù),需要寫(xiě) ->
?;蛘?,如果你手頭是指針,還要顯式地 (*object).method()
等。
在 Rust 中則不需要這么麻煩,因?yàn)?strong>自動(dòng)引用和解引用讓你可以直接寫(xiě) object.method()
。
實(shí)際上,這些調(diào)用是一樣的:
p1.distance(&p2); (&p1).distance(&p2);
Rust 會(huì)根據(jù)方法簽名(第一個(gè)參數(shù)是 &self
、&mut self
還是 self
)來(lái)自動(dòng)推斷是否需要幫你加 &
、&mut
或者 *
。這大大簡(jiǎn)化了調(diào)用方法時(shí)的語(yǔ)法。
5. 方法可以擁有多個(gè)參數(shù)
方法和函數(shù)在參數(shù)上并沒(méi)什么區(qū)別,除了第一個(gè)參數(shù)是 self
以外,其他參數(shù)你可以自由添加。
舉例來(lái)說(shuō),為 Rectangle
再定義一個(gè)方法 can_hold
,用來(lái)檢查“當(dāng)前矩形”是否可以完全容納另一個(gè)矩形:
impl Rectangle { fn can_hold(&self, other: &Rectangle) -> bool { self.width > other.width && self.height > other.height } }
然后這樣使用它:
fn main() { let rect1 = Rectangle { width: 30, height: 50 }; let rect2 = Rectangle { width: 10, height: 40 }; let rect3 = Rectangle { width: 60, height: 45 }; println!("Can rect1 hold rect2? {}", rect1.can_hold(&rect2)); // true println!("Can rect1 hold rect3? {}", rect1.can_hold(&rect3)); // false }
6. 關(guān)聯(lián)函數(shù)(Associated Functions)
如果在 impl
塊中定義的函數(shù)沒(méi)有 self
參數(shù),那它就不是方法(method),而是關(guān)聯(lián)函數(shù)(associated function)。
關(guān)聯(lián)函數(shù)常被用來(lái)提供類似“構(gòu)造函數(shù)”的功能。
舉個(gè)例子,如果你想快速構(gòu)造一個(gè)“正方形”:
impl Rectangle { // 關(guān)聯(lián)函數(shù) fn square(size: u32) -> Self { Self { width: size, height: size, } } }
調(diào)用的時(shí)候,使用 ::
語(yǔ)法來(lái)調(diào)用關(guān)聯(lián)函數(shù):
fn main() { let sq = Rectangle::square(3); println!("正方形 sq: {:#?}", sq); }
打印結(jié)果為:
正方形 sq: Rectangle {
width: 3,
height: 3
}
在標(biāo)準(zhǔn)庫(kù)里,我們也經(jīng)??吹竭@種關(guān)聯(lián)函數(shù),比如 String::from("Hello")
。它不需要某個(gè)已存在的 String
實(shí)例,就可以直接調(diào)用,用來(lái)創(chuàng)建一個(gè)新的字符串。
7. 多個(gè) impl 塊
你可以為同一個(gè)類型寫(xiě)多個(gè) impl
塊,比如:
impl Rectangle { fn area(&self) -> u32 { self.width * self.height } } impl Rectangle { fn can_hold(&self, other: &Rectangle) -> bool { self.width > other.width && self.height > other.height } }
這與把它們寫(xiě)在同一個(gè) impl
中沒(méi)有本質(zhì)差別。之所以 Rust 允許你分開(kāi)寫(xiě),是為了在某些情況下(比如涉及到泛型、trait 實(shí)現(xiàn)等)組織代碼更靈活。
8. 總結(jié)
- 方法:必須定義在某個(gè)類型(如
struct
)的impl
塊中,第一個(gè)參數(shù)是self
(可變或不可變)。方法往往用于描述該類型實(shí)例的某些行為,讀或?qū)懫鋬?nèi)部數(shù)據(jù)。 - 關(guān)聯(lián)函數(shù):在
impl
塊里定義但不包含self
參數(shù)的函數(shù)。常用于構(gòu)造新實(shí)例或提供一些與實(shí)例無(wú)關(guān)的功能。 - Rust 擁有自動(dòng)引用和解引用特性,讓我們可以簡(jiǎn)潔地使用
object.method()
來(lái)調(diào)用方法。 - 多個(gè)
impl
塊可以并存,給代碼的組織提供了很大靈活性。
通過(guò)為自定義類型定義方法,我們不僅能讓代碼更具可讀性,把相關(guān)的行為放到同一個(gè) impl
塊中,也能充分利用所有權(quán)、借用等特性來(lái)保證內(nèi)存安全和并發(fā)安全。
希望這篇文章能幫你搞清楚在 Rust 中如何編寫(xiě)方法、何時(shí)使用 &self
、&mut self
、self
,以及如何借助關(guān)聯(lián)函數(shù)讓代碼更簡(jiǎn)潔優(yōu)雅。
如果你還對(duì) Rust 中的枚舉(enum)或 trait 有興趣,不妨繼續(xù)閱讀之后的章節(jié),它們和 struct
一樣,也是構(gòu)建復(fù)雜邏輯的重要工具。
當(dāng)然,以上為個(gè)人經(jīng)驗(yàn),希望能給大家一個(gè)參考,也希望大家多多支持腳本之家。
相關(guān)文章
使用cargo install安裝Rust二進(jìn)制工具過(guò)程
cargoinstall是一個(gè)用于安裝包含可執(zhí)行目標(biāo)的Rust包的命令行工具,類似于系統(tǒng)軟件包管理器,但它為Rust開(kāi)發(fā)者提供了一種簡(jiǎn)潔的方式來(lái)安裝和管理命令行工具,安裝后,二進(jìn)制文件會(huì)存儲(chǔ)在$HOME/.cargo/bin目錄中,需要將該目錄添加到$PATH環(huán)境變量中才能在命令行中直接運(yùn)行2025-02-02Rust實(shí)現(xiàn)一個(gè)表達(dá)式Parser小結(jié)
這篇文章主要為大家介紹了Rust實(shí)現(xiàn)一個(gè)表達(dá)式Parser小結(jié),有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2022-11-11從零開(kāi)始使用Rust編寫(xiě)nginx(TLS證書(shū)快過(guò)期了)
wmproxy已用Rust實(shí)現(xiàn)http/https代理,?socks5代理,?反向代理,?負(fù)載均衡,?靜態(tài)文件服務(wù)器,websocket代理,四層TCP/UDP轉(zhuǎn)發(fā),內(nèi)網(wǎng)穿透等,本文給大家介紹從零開(kāi)始使用Rust編寫(xiě)nginx(TLS證書(shū)快過(guò)期了),感興趣的朋友一起看看吧2024-03-03rust語(yǔ)言基礎(chǔ)pub關(guān)鍵字及Some語(yǔ)法示例
這篇文章主要為大家介紹了rust語(yǔ)言基礎(chǔ)pub關(guān)鍵字及Some語(yǔ)法示例詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2023-07-07Rust捕獲全局panic并記錄進(jìn)程退出日志的方法
本文提供了捕獲全局panic并記錄進(jìn)程退出日志的方法,首先使用 panic::set_hook 注冊(cè)異常處理及panic 觸發(fā)異常,結(jié)合實(shí)例代碼給大家介紹的非常詳細(xì),感興趣的朋友跟隨小編一起看看吧2024-04-04Rust實(shí)現(xiàn)構(gòu)建器模式和如何使用Bon庫(kù)中的構(gòu)建器
這篇文章主要介紹了Rust實(shí)現(xiàn)構(gòu)建器模式和如何使用Bon庫(kù)中的構(gòu)建器,本文給大家介紹的非常詳細(xì),感興趣的朋友跟隨小編一起看看吧2024-08-08