30天拿下Rust之面向?qū)ο螅╮ust面向過(guò)程)
概述
在編程語(yǔ)言的世界中,Rust以其獨(dú)特的內(nèi)存安全、并發(fā)控制和高性能特性吸引了眾多開(kāi)發(fā)者。雖然Rust并非傳統(tǒng)的面向?qū)ο缶幊陶Z(yǔ)言(比如:C 、Java),但它依然支持并提供了一種頗具特色的面向?qū)ο缶幊谭绞?,以?shí)現(xiàn)類(lèi)似于面向?qū)ο蟮木幊谭妒健?/p>
在Rust中,沒(méi)有類(lèi)的概念,但提供了模塊、結(jié)構(gòu)體、枚舉、Trait來(lái)模擬面向?qū)ο缶幊痰娜筇匦裕悍庋b、繼承和多態(tài)。下面,我們分別進(jìn)行介紹。
封裝
Rust的封裝機(jī)制提供了一種強(qiáng)大的方式來(lái)隱藏實(shí)現(xiàn)細(xì)節(jié),僅暴露必要的接口給使用者。封裝是面向?qū)ο缶幊痰娜蠡咎匦灾?,它有助于?chuàng)建模塊化的代碼,提高代碼的可維護(hù)性和安全性。在Rust中,封裝主要通過(guò)模塊、結(jié)構(gòu)體、私有性等特性來(lái)實(shí)現(xiàn)。
Rust使用模塊來(lái)組織代碼,每個(gè)模塊都有自己的作用域,可以包含函數(shù)、類(lèi)型定義、其他模塊等。模塊提供了一種自然的封裝方式,可以將相關(guān)的代碼組織在一起,并通過(guò)pub關(guān)鍵字來(lái)控制哪些內(nèi)容對(duì)外部可見(jiàn)。在之前的專(zhuān)欄文章中,我們?cè)鴮?zhuān)門(mén)介紹過(guò)模塊,故這里就不再進(jìn)一步展開(kāi)了。
在Rust中,結(jié)構(gòu)體的字段可以通過(guò)指定訪(fǎng)問(wèn)修飾符來(lái)控制其可見(jiàn)性。默認(rèn)情況下,字段是私有的,這意味著它們只能在定義結(jié)構(gòu)體的模塊內(nèi)部被訪(fǎng)問(wèn)。通過(guò)pub關(guān)鍵字,我們可以將字段設(shè)置為公有,以便在外部訪(fǎng)問(wèn)。
我們?cè)谙旅娴膍y_module.rs文件中聲明了公開(kāi)的函數(shù)public_func和公開(kāi)的結(jié)構(gòu)體Publicstruct。private_func函數(shù)由于沒(méi)有使用pub關(guān)鍵字,默認(rèn)為私有的。
// my_module.rspub fn public_func() { // ...}fn private_func() { // ...}pub struct PublicStruct { pub public_field: i32,}
接著,我們?cè)谙旅娴膍ain.rs文件中使用了模塊my_module中的函數(shù)和結(jié)構(gòu)體。由于private_func是私有的,因此,無(wú)法使用use關(guān)鍵字導(dǎo)入,編譯會(huì)提示錯(cuò)誤:function `private_func` is private。
// main.rsmod my_module;use my_module::PublicStruct;use my_module::public_func;// 錯(cuò)誤:該函數(shù)是私有的,無(wú)法使用use my_module::private_func;fn main() { let data = PublicStruct { public_field: 66 }; println!("{}", data.public_field); public_func();}
繼承
Rust并沒(méi)有傳統(tǒng)意義上的繼承機(jī)制,更傾向于使用組合和Trait來(lái)復(fù)用和擴(kuò)展代碼。然而,通過(guò)一些模式,我們可以在Rust中實(shí)現(xiàn)類(lèi)似繼承的效果。
使用組合模擬繼承
可以通過(guò)將一個(gè)類(lèi)型作為另一個(gè)類(lèi)型的字段來(lái)實(shí)現(xiàn)組合,這可以模擬繼承中子類(lèi)包含父類(lèi)字段的效果。
struct Parent { value: i32,}impl Parent { fn do_something(&self) { println!("parent data: {}", self.value); }}struct Child { parent: Parent, extra_value: String,}impl Child { fn new(value: i32, extra_field: String) -> Child { Child { parent: Parent { value }, extra_value: extra_field, } } fn do_child_thing(&self) { println!("child data: {}", self.extra_value); } // 委托給父類(lèi)的方法 fn do_something(&self) { self.parent.do_something(); }}fn main() { let child = Child::new(66, "CSDN".to_string()); // 調(diào)用父類(lèi)的方法 child.do_something(); // 調(diào)用子類(lèi)的方法 child.do_child_thing();}
在上面的示例代碼中,Child結(jié)構(gòu)體包含一個(gè)Parent類(lèi)型的字段parent。這允許Child訪(fǎng)問(wèn)和調(diào)用Parent的方法,從而模擬了繼承的行為。同時(shí),Child還可以添加自己的字段和方法。
使用Trait模擬接口繼承
Trait在Rust中類(lèi)似于接口,它們定義了一組方法簽名,可以由不同的類(lèi)型來(lái)實(shí)現(xiàn),這可以模擬接口繼承的效果。
trait Animal { fn speak(&self);}struct Dog { name: String,}impl Animal for Dog { fn speak(&self) { println!("dog {} speak", self.name); }}struct Cat { name: String,}impl Animal for Cat { fn speak(&self) { println!("cat {} speak", self.name); }}fn animal_speak(animal: &dyn Animal) { animal.speak();}fn main() { let dog = Dog { name: "Buddy".to_string() }; let cat = Cat { name: "Whiskers".to_string() }; animal_speak(&dog); animal_speak(&cat);}
在上面的示例代碼中,我們定義了一個(gè)Animal特征,它有一個(gè)speak方法。Dog和Cat結(jié)構(gòu)體都實(shí)現(xiàn)了Animal特征,因此它們都可以被視為動(dòng)物,并且具有speak方法。通過(guò)動(dòng)態(tài)分發(fā)(使用&dyn Animal),我們可以編寫(xiě)接受任何實(shí)現(xiàn)了Animal特征的類(lèi)型的函數(shù),比如這里的animal_speak。
多態(tài)
在Rust中,多態(tài)通常是通過(guò)Trait和泛型來(lái)實(shí)現(xiàn)的。多態(tài)允許我們編寫(xiě)靈活的代碼,這些代碼可以處理多種不同的類(lèi)型,只要這些類(lèi)型滿(mǎn)足某些共同的接口或約束。Trait定義了類(lèi)型必須實(shí)現(xiàn)的方法集合,從而允許我們編寫(xiě)與這些類(lèi)型交互的通用代碼。在上面介紹繼承的示例代碼中,我們已經(jīng)看到了基于Trait的多態(tài)實(shí)現(xiàn),故這里就不再贅述了。
接下來(lái),我們使用泛型來(lái)實(shí)現(xiàn)多態(tài)。泛型允許我們編寫(xiě)可以處理多種類(lèi)型的函數(shù)或結(jié)構(gòu)體,而不需要在編譯時(shí)指定具體的類(lèi)型。
fn find_max<T: Ord>(slice: &[T]) -> &T { let mut max = &slice[0]; for item in slice.iter() { if item > max { max = item; } } max}fn main() { let numbers = vec![66, 99, 100, 50]; let max_number = *find_max(&numbers); println!("{}", max_number); let fruits = vec!["Lemon", "Apple", "Date"]; let max_fruit = find_max(&fruits); println!("{}", max_fruit);}
在上面的示例代碼中,我們定義了一個(gè)泛型函數(shù)find_max,它接受一個(gè)實(shí)現(xiàn)了Ord特征(即可以排序的類(lèi)型)的切片,并返回其中的最大值。由于Ord特征是由多種標(biāo)準(zhǔn)庫(kù)類(lèi)型實(shí)現(xiàn)的,我們可以使用這個(gè)函數(shù)來(lái)找出整數(shù)切片中的最大值,或字符串切片中基于字典序的最大字符串。
總結(jié)
雖然Rust并不是傳統(tǒng)意義上的面向?qū)ο缶幊陶Z(yǔ)言,但它提供了豐富的工具來(lái)模擬和實(shí)現(xiàn)面向?qū)ο蟮母拍?。通過(guò)結(jié)構(gòu)體與方法的組合、Trait與接口的定義、泛型的使用,Rust可以讓我們以面向?qū)ο蟮姆绞絹?lái)組織和封裝代碼,實(shí)現(xiàn)高內(nèi)聚、低耦合的代碼結(jié)構(gòu)。正是這種靈活性,使得Rust能夠適應(yīng)各種復(fù)雜的編程需求,成為系統(tǒng)級(jí)編程的理想選擇。