国产chinesehdxxxx野外,国产av无码专区亚洲av琪琪,播放男人添女人下边视频,成人国产精品一区二区免费看,chinese丰满人妻videos

Rust 面向?qū)ο笳Z(yǔ)言的特征

2023-03-22 15:15 更新
ch17-01-what-is-oo.md
commit 3fa4eeca3a57f257e3569055d808b6a76e9b70ee

關(guān)于一個(gè)語(yǔ)言被稱為面向?qū)ο笏璧墓δ?,在編程社區(qū)內(nèi)并未達(dá)成一致意見。Rust 被很多不同的編程范式影響,包括面向?qū)ο缶幊蹋槐热绲谑绿岬搅藖?lái)自函數(shù)式編程的特性。面向?qū)ο缶幊陶Z(yǔ)言所共享的一些特性往往是對(duì)象、封裝和繼承。讓我們看一下這每一個(gè)概念的含義以及 Rust 是否支持他們。

對(duì)象包含數(shù)據(jù)和行為

由 Erich Gamma、Richard Helm、Ralph Johnson 和 John Vlissides(Addison-Wesley Professional, 1994)編寫的書 Design Patterns: Elements of Reusable Object-Oriented Software 被俗稱為 The Gang of Four (字面意思為 “四人幫”),它是面向?qū)ο缶幊棠J降哪夸洝K@樣定義面向?qū)ο缶幊蹋?

Object-oriented programs are made up of objects. An object packages both data and the procedures that operate on that data. The procedures are typically called methods or operations.

面向?qū)ο蟮某绦蚴怯蓪?duì)象組成的。一個(gè) 對(duì)象 包含數(shù)據(jù)和操作這些數(shù)據(jù)的過(guò)程。這些過(guò)程通常被稱為 方法 或 操作。

在這個(gè)定義下,Rust 是面向?qū)ο蟮模航Y(jié)構(gòu)體和枚舉包含數(shù)據(jù)而 impl 塊提供了在結(jié)構(gòu)體和枚舉之上的方法。雖然帶有方法的結(jié)構(gòu)體和枚舉并不被 稱為 對(duì)象,但是他們提供了與對(duì)象相同的功能,參考 The Gang of Four 中對(duì)象的定義。

封裝隱藏了實(shí)現(xiàn)細(xì)節(jié)

另一個(gè)通常與面向?qū)ο缶幊滔嚓P(guān)的方面是 封裝encapsulation)的思想:對(duì)象的實(shí)現(xiàn)細(xì)節(jié)不能被使用對(duì)象的代碼獲取到。所以唯一與對(duì)象交互的方式是通過(guò)對(duì)象提供的公有 API;使用對(duì)象的代碼無(wú)法深入到對(duì)象內(nèi)部并直接改變數(shù)據(jù)或者行為。封裝使得改變和重構(gòu)對(duì)象的內(nèi)部時(shí)無(wú)需改變使用對(duì)象的代碼。

就像我們?cè)诘谄哒掠懻摰哪菢樱嚎梢允褂?nbsp;pub 關(guān)鍵字來(lái)決定模塊、類型、函數(shù)和方法是公有的,而默認(rèn)情況下其他一切都是私有的。比如,我們可以定義一個(gè)包含一個(gè) i32 類型 vector 的結(jié)構(gòu)體 AveragedCollection 。結(jié)構(gòu)體也可以有一個(gè)字段,該字段保存了 vector 中所有值的平均值。這樣,希望知道結(jié)構(gòu)體中的 vector 的平均值的人可以隨時(shí)獲取它,而無(wú)需自己計(jì)算。換句話說(shuō),AveragedCollection 會(huì)為我們緩存平均值結(jié)果。示例 17-1 有 AveragedCollection 結(jié)構(gòu)體的定義:

文件名: src/lib.rs

pub struct AveragedCollection {
    list: Vec<i32>,
    average: f64,
}

示例 17-1: AveragedCollection 結(jié)構(gòu)體維護(hù)了一個(gè)整型列表和集合中所有元素的平均值。

注意,結(jié)構(gòu)體自身被標(biāo)記為 pub,這樣其他代碼就可以使用這個(gè)結(jié)構(gòu)體,但是在結(jié)構(gòu)體內(nèi)部的字段仍然是私有的。這是非常重要的,因?yàn)槲覀兿MWC變量被增加到列表或者被從列表刪除時(shí),也會(huì)同時(shí)更新平均值。可以通過(guò)在結(jié)構(gòu)體上實(shí)現(xiàn) add、remove 和 average 方法來(lái)做到這一點(diǎn),如示例 17-2 所示:

文件名: src/lib.rs

impl AveragedCollection {
    pub fn add(&mut self, value: i32) {
        self.list.push(value);
        self.update_average();
    }

    pub fn remove(&mut self) -> Option<i32> {
        let result = self.list.pop();
        match result {
            Some(value) => {
                self.update_average();
                Some(value)
            }
            None => None,
        }
    }

    pub fn average(&self) -> f64 {
        self.average
    }

    fn update_average(&mut self) {
        let total: i32 = self.list.iter().sum();
        self.average = total as f64 / self.list.len() as f64;
    }
}

示例 17-2: 在AveragedCollection 結(jié)構(gòu)體上實(shí)現(xiàn)了add、remove 和 average 公有方法

公有方法 addremove 和 average 是修改 AveragedCollection 實(shí)例的唯一方式。當(dāng)使用 add 方法把一個(gè)元素加入到 list 或者使用 remove 方法來(lái)刪除時(shí),這些方法的實(shí)現(xiàn)同時(shí)會(huì)調(diào)用私有的 update_average 方法來(lái)更新 average 字段。

list 和 average 是私有的,所以沒(méi)有其他方式來(lái)使得外部的代碼直接向 list 增加或者刪除元素,否則 list 改變時(shí)可能會(huì)導(dǎo)致 average 字段不同步。average 方法返回 average 字段的值,這使得外部的代碼只能讀取 average 而不能修改它。

因?yàn)槲覀円呀?jīng)封裝好了 AveragedCollection 的實(shí)現(xiàn)細(xì)節(jié),將來(lái)可以輕松改變類似數(shù)據(jù)結(jié)構(gòu)這些方面的內(nèi)容。例如,可以使用 HashSet<i32> 代替 Vec<i32> 作為 list 字段的類型。只要 add、remove 和 average 公有函數(shù)的簽名保持不變,使用 AveragedCollection 的代碼就無(wú)需改變。相反如果使得 list 為公有,就未必都會(huì)如此了: HashSet<i32> 和 Vec<i32> 使用不同的方法增加或移除項(xiàng),所以如果要想直接修改 list 的話,外部的代碼可能不得不做出修改。

如果封裝是一個(gè)語(yǔ)言被認(rèn)為是面向?qū)ο笳Z(yǔ)言所必要的方面的話,那么 Rust 滿足這個(gè)要求。在代碼中不同的部分使用 pub 與否可以封裝其實(shí)現(xiàn)細(xì)節(jié)。

繼承,作為類型系統(tǒng)與代碼共享

繼承Inheritance)是一個(gè)很多編程語(yǔ)言都提供的機(jī)制,一個(gè)對(duì)象可以定義為繼承另一個(gè)對(duì)象的定義,這使其可以獲得父對(duì)象的數(shù)據(jù)和行為,而無(wú)需重新定義。

如果一個(gè)語(yǔ)言必須有繼承才能被稱為面向?qū)ο笳Z(yǔ)言的話,那么 Rust 就不是面向?qū)ο蟮?。無(wú)法定義一個(gè)結(jié)構(gòu)體繼承父結(jié)構(gòu)體的成員和方法。然而,如果你過(guò)去常常在你的編程工具箱使用繼承,根據(jù)你最初考慮繼承的原因,Rust 也提供了其他的解決方案。

選擇繼承有兩個(gè)主要的原因。第一個(gè)是為了重用代碼:一旦為一個(gè)類型實(shí)現(xiàn)了特定行為,繼承可以對(duì)一個(gè)不同的類型重用這個(gè)實(shí)現(xiàn)。相反 Rust 代碼可以使用默認(rèn) trait 方法實(shí)現(xiàn)來(lái)進(jìn)行共享,在示例 10-14 中我們見過(guò)在 Summary trait 上增加的 summarize 方法的默認(rèn)實(shí)現(xiàn)。任何實(shí)現(xiàn)了 Summary trait 的類型都可以使用 summarize 方法而無(wú)須進(jìn)一步實(shí)現(xiàn)。這類似于父類有一個(gè)方法的實(shí)現(xiàn),而通過(guò)繼承子類也擁有這個(gè)方法的實(shí)現(xiàn)。當(dāng)實(shí)現(xiàn) Summary trait 時(shí)也可以選擇覆蓋 summarize 的默認(rèn)實(shí)現(xiàn),這類似于子類覆蓋從父類繼承的方法實(shí)現(xiàn)。

第二個(gè)使用繼承的原因與類型系統(tǒng)有關(guān):表現(xiàn)為子類型可以用于父類型被使用的地方。這也被稱為 多態(tài)polymorphism),這意味著如果多種對(duì)象共享特定的屬性,則可以相互替代使用。

多態(tài)(Polymorphism)

很多人將多態(tài)描述為繼承的同義詞。不過(guò)它是一個(gè)有關(guān)可以用于多種類型的代碼的更廣泛的概念。對(duì)于繼承來(lái)說(shuō),這些類型通常是子類。 Rust 則通過(guò)泛型來(lái)對(duì)不同的可能類型進(jìn)行抽象,并通過(guò) trait bounds 對(duì)這些類型所必須提供的內(nèi)容施加約束。這有時(shí)被稱為 bounded parametric polymorphism

近來(lái)繼承作為一種語(yǔ)言設(shè)計(jì)的解決方案在很多語(yǔ)言中失寵了,因?yàn)槠鋾r(shí)常帶有共享多于所需的代碼的風(fēng)險(xiǎn)。子類不應(yīng)總是共享其父類的所有特征,但是繼承卻始終如此。如此會(huì)使程序設(shè)計(jì)更為不靈活,并引入無(wú)意義的子類方法調(diào)用,或由于方法實(shí)際并不適用于子類而造成錯(cuò)誤的可能性。某些語(yǔ)言還只允許子類繼承一個(gè)父類,進(jìn)一步限制了程序設(shè)計(jì)的靈活性。

因?yàn)檫@些原因,Rust 選擇了一個(gè)不同的途徑,使用 trait 對(duì)象而不是繼承。讓我們看一下 Rust 中的 trait 對(duì)象是如何實(shí)現(xiàn)多態(tài)的。


以上內(nèi)容是否對(duì)您有幫助:
在線筆記
App下載
App下載

掃描二維碼

下載編程獅App

公眾號(hào)
微信公眾號(hào)

編程獅公眾號(hào)