国产 无码 综合区,色欲AV无码国产永久播放,无码天堂亚洲国产AV,国产日韩欧美女同一区二区

【Rust筆記】意譯解構(gòu) Object Safety for trait

這篇具有很好參考價(jià)值的文章主要介紹了【Rust筆記】意譯解構(gòu) Object Safety for trait。希望對大家有所幫助。如果存在錯(cuò)誤或未考慮完全的地方,請大家不吝賜教,您也可以點(diǎn)擊"舉報(bào)違法"按鈕提交疑問。

意譯解構(gòu)Object Safety for trait

借助【虛表vtable】對被調(diào)用成員函數(shù)【運(yùn)行時(shí)·內(nèi)存尋址】的作法允許系統(tǒng)編程語言Rust模仿出OOP高級(jí)計(jì)算機(jī)語言才具備的【專用·多態(tài)Ad-hoc Polymorphism】特性。

計(jì)算機(jī)高級(jí)語言中的“多態(tài)”術(shù)語是一個(gè)泛指。它通??杀患?xì)化為

  • 基于繼承關(guān)系的“子類·多態(tài)”?Subtype Polymorphism?— 形狀相似而類名不同即是不同。重“名分”輕“事實(shí)”。代表語言JAVA

  • 基于接口抽象的“專用·多態(tài)”?Ad-hoc Polymorphism?—?突出不同類型間的共性,淡化類型差異

  • 基于“鴨子類型”的“·多態(tài)”Row Polymorphism?— 類名不同卻形狀相似即是相兼容。重“事實(shí)”輕“名分”。代表語言JS

因?yàn)?code>Rust不支持類繼承,所以它的多態(tài)方式僅收斂于

  • 由【trait Object?+?trait method動(dòng)態(tài)分派】的“專用·多態(tài)”

  • 由【Lens設(shè)計(jì)模式 + 過程宏】的“行·多態(tài)”

僅拋磚引玉,就不再展開了。

Rust生產(chǎn)實(shí)踐而言,這也是“以時(shí)間換空間”縮小編譯輸出二進(jìn)制文件體積的絕佳手段。其對WEB匯編技術(shù)方向更是意義深遠(yuǎn),因?yàn)橹灰阅軌蛴茫?code>WASM體積越小越好。對webapp來講,用過剩的性能換取發(fā)布包更小的體積還是很劃算的。但,rustc要求凡是參與【專用多態(tài)】抽象的trait都必須Object Safety?!皩ο蟀踩钡闹形闹弊g非常令人費(fèi)解。

但結(jié)合【專用多態(tài)】技術(shù)語境,Object Safety可“啰嗦地”意譯表達(dá)為:“trait method調(diào)用端不需要trait實(shí)現(xiàn)類及其實(shí)例對象有任何了解與假設(shè),而僅憑trait描述自身,就能順利地尋址和執(zhí)行trait method,以及獲得trait method執(zhí)行反饋”。因此,Safety不是直譯的“安全”,而是意譯的“不知”。

@Rustacean 也可將Object Safety精煉地領(lǐng)會(huì)為“對象不知”或倒裝一下“不知(類型與)對象(就能執(zhí)行它的成員方法)”。

trait對象安全的核心原則

【專用多態(tài)】抽象要求trait將其具體實(shí)現(xiàn)類以【動(dòng)態(tài)大小類型DST】的?Sized形式呈現(xiàn)給trait method調(diào)用端。即,胖指針(= 數(shù)據(jù)指針 + 虛表指針)

  • 在編譯時(shí),不鎖定數(shù)據(jù)類型。但因指針大小是固定的,所以編譯操作依舊能夠成功完成。

  • 在運(yùn)行時(shí),實(shí)時(shí)度量變量大小,不論它是【堆】變量Box<dyn Trait>,還是【?!孔兞?code>&dyn Trait。

以代碼語言概括之,trait和(動(dòng)態(tài)分派)trait method都必須滿足DSTwhere Self: ?Sized限定條件。事實(shí)上,where Self: ?Sized也是rustctrait自身與trait關(guān)聯(lián)函數(shù)的默認(rèn)限定

名詞解釋:

  • DST縮寫詞的全稱Dynamic Sized Type。其含義是“運(yùn)行時(shí)確定大小的數(shù)據(jù)類型”。所以,它的trait限定條件是?Sized。

  • FST縮寫詞的全稱Fixed Sized Type。其含義是“編譯時(shí)確定大小的數(shù)據(jù)類型”。所以,它的trait限定條件是Sized。

對照【泛型類型參數(shù)】記憶

對照點(diǎn)一:

  • 泛型類型參數(shù)默認(rèn)是FST,但可where T: ?Sized選擇退出默認(rèn)約定

  • traittrait method缺省都是DST,但同時(shí)也支持where Self: Sized選擇退出初始限定

對照點(diǎn)二:例程1

  • 泛型類型參數(shù)的Sized限定條件是可以被書面重申的,雖然這完全沒有必要。

  • traittrait method定義卻不能書面地限定where Self: ?Sized。這會(huì)導(dǎo)致編譯失敗,因?yàn)?code>?Sized僅能書面地限定泛型類型參數(shù)(的形參)。

判斷trait是否對象安全的極簡checklist

舊版The Rust Programming Language教程曾經(jīng)列舉過操作性極強(qiáng)的篩選標(biāo)準(zhǔn):

  1. trait method返回值類型不是Self

  2. trait method不是【泛型函數(shù)】

雖至今其仍在互聯(lián)網(wǎng)上廣為流傳,但它對知識(shí)內(nèi)核的過度簡化極易誤導(dǎo) @Rustacean 認(rèn)為Object Safe trait的全部trait method都必須是【動(dòng)態(tài)分派】的。其實(shí)不然,對象安全trait也被允許包含編譯時(shí)【靜態(tài)分派】的成員方法。事實(shí)上,只要trait自身滿足Object Safety基本規(guī)則,它的成員方法

  • 既可以被收錄入vtable和參與【動(dòng)態(tài)分派】 — 對trait method隱式類型參數(shù)Self不做任何限定

  • 也能編譯時(shí)被單態(tài)化和參與【靜態(tài)分派】 — 以where Self: Sized限定trait method隱式類型參數(shù)Self

同一個(gè)trait定義動(dòng)/靜兩用,沒毛??!例程2?走出這個(gè)知識(shí)點(diǎn)誤區(qū)有助于避免在業(yè)務(wù)功能開發(fā)過程中頻繁地“鉆牛角尖”和減輕心智痛苦。

trait自身對象安全的基本原則

  1. trait定義的隱式類型參數(shù)Self必須是?Sized的。這也意味著:

    1. 若有supertrait,那么supertrait也必須是?Sized的,因?yàn)?code>trait Trait: Supertrait {}就是trait Trait where Self: Supertrait {}的語法糖。例程3

      // 因?yàn)閌supertrait`不是`?Sized`,所以該`trait`不是`Object Safety`的。
      trait Trait: Sized {}
      // 等效寫法 - trait Trait where Self: Supertrait {}
      struct S;
      impl Trait for S {}
      let obj: Box<dyn Trait> = Box::new(S); // 不可動(dòng)態(tài)分派。
    2. supertrait是泛型trait,那么supertrait泛型類型參數(shù)的實(shí)參一定不能是Self,因?yàn)?code>Self編譯時(shí)類型不確定和不能作為單態(tài)化參數(shù)。例程4

      trait Super<A> {}
      // 該`trait`不是`Object Safety`的,因?yàn)樗碾[式類型參數(shù)`Self`是`Sized`的。
      // - 若抹掉`trait`的`where`從句,那么泛型的【靜態(tài)分派】會(huì)抱怨:“編譯時(shí),Self的
      //   類型大小未知”。總之,左右為難。
      trait Trait: Super<Self> where Self: Sized {}
      struct S;
      impl<A> Super<A> for S {}
      impl Trait for S {}
      let obj: Box<dyn Trait> = Box::new(S); // 失敗,因?yàn)閌Self: Sized`
  2. trait定義不能包含【關(guān)聯(lián)常量】。例程5

    // 該`trait`不是`Object Safety`的,
    trait NotObjectSafe {
        // 因?yàn)樗恕娟P(guān)聯(lián)常量】
        const CONST: i32 = 1;
    }
    struct S;
    impl NotObjectSafe for S {}
    let obj: Box<dyn NotObjectSafe> = Box::new(S);
  3. trait定義中成員方法【關(guān)聯(lián)函數(shù)】的隱式類型參數(shù)Self必須被顯式地限定為Sized?例程6。即,where Self: Sized。

    // `trait`不是`Object Safety`,因?yàn)?trait NotObjectSafe {
        // 它的非成員方法關(guān)聯(lián)函數(shù)的隱式類型參數(shù)`Self`不是`Sized`,
        // 而是缺省的`?Sized`
        fn foo() {}
    }
    struct S;
    impl NotObjectSafe for S {}
    let obj: Box<dyn NotObjectSafe> = Box::new(S); // 編譯失敗

    因?yàn)殡[式類型參數(shù)Self的缺省限定條件就是?Sized,所以 @Rustacean 需要利用where從句書面地退出初始限定和重置SelfSized的。

    // `trait`是`Object Safety`,因?yàn)?trait NotObjectSafe {
        // 它的非成員方法關(guān)聯(lián)函數(shù)的隱式類型參數(shù)`Self`被顯式地限定為`Sized`,
        fn foo() where Self: Sized {}
    }
    struct S;
    impl NotObjectSafe for S {}
    let obj: Box<dyn NotObjectSafe> = Box::new(S); // 編譯成功

至此,若不考慮trait method,獲得一個(gè)【對象安全】的trait并不難。

對象安全trait的成員方法

【重申強(qiáng)調(diào)】即便trait定義的全部成員方法都不參與【動(dòng)態(tài)分派】(即,與它配對的虛表是空),但只要滿足上節(jié)羅列的三項(xiàng)條件,該trait依舊是“對象安全”的。只不過,它的trait Object沒啥實(shí)用意義。

靜態(tài)分派trait method

因?yàn)?code>trait【關(guān)聯(lián)函數(shù)】的缺省抽象形式是【動(dòng)態(tài)分派】,所以 @Rustacean 需要顯式地將trait method隱式類型參數(shù)Self限定為Sized。即,給trait method聲明添加where Self: Sized限定條件和退出DST內(nèi)存布局模式?例程7。然后,你就再也不用擔(dān)心這些trait method

  • 是否是【泛型函數(shù)】

  • self形參與返回值類型是否是Self

  • self參數(shù)數(shù)據(jù)類型

雖然省心了,但胖指針(堆Box<dyn Trait>或棧&dyn Trait)也再點(diǎn)不出這些trait method了。請仔細(xì)閱讀下面例程代碼中的注釋和體會(huì)其中的差別。

// 雖然`trait`是`Object Safety`,
trait Trait {
    // (1) 但它的`trait method`都是靜態(tài)分派的,和不能從`Box<dyn Trait>`上被調(diào)用
    //      — `trait method`的隱式類型參數(shù)`Self`都被顯示地限定為`Sized`的,
    // (2) 于是,成員方法的
    fn returns(&self) -> Self    // a. 返回值類型被允許是`Self`
        where Self: Sized;
    fn param(&self, other: Self) // b. 非`self`形參也被允許是`Self`數(shù)據(jù)類型
        where Self: Sized {}
    fn typed<T>(&self, x: T)     // c. 接受【泛型函數(shù)】成員方法
        where Self: Sized {}
    // (3) 非成員方法的關(guān)聯(lián)函數(shù)必須是靜態(tài)分派的
    fn foo()
        where Self: Sized {}     // 手工限定其是靜態(tài)分派函數(shù)
}
struct S;
impl Trait for S {
    fn returns(&self) -> Self where Self: Sized { S {field: 10} }
}
// 雖然`trait`是`Object Safety`,但
let obj: Box<dyn Trait> = Box::new(S {field: 12});
// (1) 它沒有可運(yùn)行時(shí)尋址調(diào)用的成員方法。
// obj.returns(); // 失敗,因?yàn)? where Self: Sized
// (2) 它的`trait method`都必須從實(shí)現(xiàn)類的實(shí)例對象上被調(diào)用
<S as Trait>::foo();
let obj = S {field: 13};
obj.returns();
obj.typed(1);

對象安全的動(dòng)態(tài)分派trait method

雖然【動(dòng)態(tài)分派】是全部trait method的“天賦技能”,但 @Rustacean 也有義務(wù)從編程環(huán)節(jié)確保trait method不依賴于trait實(shí)現(xiàn)類的任何【元信息】。即,trait method函數(shù)體對trait實(shí)現(xiàn)類的類型信息不知。

“不知”即是“安全”。“對象安全”還真不如意譯為“對象不知”。這多有趣呀!

在書面代碼上,@Rustacean 僅需要做到在trait method定義中,

  1. 不出現(xiàn)【泛型類型參數(shù)】?例程8。例外,【泛型生命周期參數(shù)】還是被允許的。例程9

  2. self形參與返回值類型不能是Self。關(guān)鍵字Self代指trait實(shí)現(xiàn)類,但Object safe trait需要對實(shí)現(xiàn)類不知。

  3. self形參的數(shù)據(jù)類型必須是如下六種之一?例程10

    1. 只讀引用&Self / &self

    2. 可修改引用&mut Self / &mut self

    3. 智能指針Box<Self>

    4. 引用計(jì)數(shù)Rc<Self>

    5. 原子引用計(jì)數(shù)Arc<Self>

    6. 不可swap內(nèi)存Pin<P>。其中,泛型類型參數(shù)P可以是前五種類型中的任意一種。

  4. 千萬別限定trait method的隱式類型參數(shù)SelfSized。

條條框框還是比較多的,可得常記頻用,才可應(yīng)用自如。

對象安全trait的非成員方法關(guān)聯(lián)函數(shù)

這類associated functions概念對等于Typescript靜態(tài)成員方法?!办o態(tài)”意味著這類關(guān)聯(lián)函數(shù)一定不會(huì)參與動(dòng)態(tài)分派,但出于未知原因rustc依舊偏好將其收錄虛表vtable和造成trait Object實(shí)例化失敗。所以,Object safe trait的重要原則之一,就是:

  • 要么,沒有非成員方法關(guān)聯(lián)函數(shù)

  • 要么,顯式地書面限定每個(gè)非成員方法關(guān)聯(lián)函數(shù)的隱式類型參數(shù)SelfSized。例程11

否則,編譯失敗。

// `trait Trait`不是對象安全的,
trait Trait {
    // 因?yàn)樗姆浅蓡T方法關(guān)聯(lián)函數(shù)不可動(dòng)態(tài)分派,但還被收錄`vtable`
    fn foo() {} // 給加添加`where Self: Sized`限定條件,可解編譯失敗
}
struct S;
impl Trait for S {}
let obj: Box<dyn Trait> = Box::new(S);

結(jié)束語

【動(dòng)態(tài)分派】是traittrait method初始開啟的天賦技能。除了性能極客,@Rustacean 一般想不起刻意地對定它們做靜態(tài)化處理。但,由于項(xiàng)目歷史包袱,在舊trait定義內(nèi)遺留的

  • 泛型函數(shù)

  • Self濫用

  • 非成員方法關(guān)聯(lián)函數(shù)

導(dǎo)致其不再“對象安全”。咱們既不必埋怨舊代碼作者(哎!誰的認(rèn)知不是逐步深化的呀),也別慌,更別像我一樣傻乎乎地立即重構(gòu)代碼(很的)。而僅只需要將僅能靜態(tài)分派關(guān)聯(lián)函數(shù)的隱式類型參數(shù)Self限定為Sized即可。只要虛表不再收錄它們,rustc就不會(huì)抱怨了。于是,“同一個(gè)trait既兼容于新/舊代碼,還動(dòng)/靜兩用”豈不美哉?例程12!可是不值得炫技,因?yàn)榇罅窟@類trait代碼是餒餒的后期維護(hù)心智災(zāi)難 — 只能算是變通的“歪招”。

這次分享的內(nèi)容就是這些。創(chuàng)作不易,希望路過的神仙哥哥、仙女妹妹們評(píng)論、點(diǎn)贊、轉(zhuǎn)發(fā)呀!相信我在【WEB匯編】技術(shù)方向Rust棧至今都是最優(yōu)選擇。

【Rust筆記】意譯解構(gòu) Object Safety for trait,rust,筆記,開發(fā)語言,后端文章來源地址http://www.zghlxwxcb.cn/news/detail-616445.html

到了這里,關(guān)于【Rust筆記】意譯解構(gòu) Object Safety for trait的文章就介紹完了。如果您還想了解更多內(nèi)容,請?jiān)谟疑辖撬阉鱐OY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!

本文來自互聯(lián)網(wǎng)用戶投稿,該文觀點(diǎn)僅代表作者本人,不代表本站立場。本站僅提供信息存儲(chǔ)空間服務(wù),不擁有所有權(quán),不承擔(dān)相關(guān)法律責(zé)任。如若轉(zhuǎn)載,請注明出處: 如若內(nèi)容造成侵權(quán)/違法違規(guī)/事實(shí)不符,請點(diǎn)擊違法舉報(bào)進(jìn)行投訴反饋,一經(jīng)查實(shí),立即刪除!

領(lǐng)支付寶紅包贊助服務(wù)器費(fèi)用

相關(guān)文章

  • 【Rust 基礎(chǔ)篇】Rust派生宏:自動(dòng)實(shí)現(xiàn)trait的魔法

    Rust是一門現(xiàn)代的、安全的系統(tǒng)級(jí)編程語言,它提供了豐富的元編程特性,其中派生宏(Derive Macros)是其中之一。派生宏允許開發(fā)者自定義類型上的trait實(shí)現(xiàn),從而在編譯期間自動(dòng)實(shí)現(xiàn)trait。在本篇博客中,我們將深入探討Rust中的派生宏,包括派生宏的定義、使用方法以及一些

    2024年02月14日
    瀏覽(17)
  • 研讀Rust圣經(jīng)解析——Rust learn-16(高級(jí)trait,宏)

    研讀Rust圣經(jīng)解析——Rust learn-16(高級(jí)trait,宏)

    我們使用type即可聲明一個(gè)關(guān)聯(lián)類型,關(guān)聯(lián)類型的作用就是簡化和隱藏顯示類型(個(gè)人認(rèn)為) 簡化:一個(gè)很長的類型總是被需要時(shí),需要開發(fā)者耗費(fèi)精力的重復(fù)書寫,而且若有改動(dòng),則需要改多個(gè)地方 隱藏:對外部調(diào)用者隱藏,外部調(diào)用者無需知道它指的是什么,只要

    2024年02月02日
    瀏覽(19)
  • Rust-trait

    Rust-trait

    Rust語言中的trait是非常重要的概念。 在Rust中,trait這一個(gè)概念承擔(dān)了多種職責(zé)。在中文里,trait可以翻譯為“特征”“特點(diǎn)”“特性”等。 trait中可以定義函數(shù)。用例子來說明,我們定義如下的trait: 上面這個(gè)trait包含了一個(gè)方法,這個(gè)方法只有一個(gè)參數(shù),這個(gè)self參數(shù)是什么意

    2024年01月20日
    瀏覽(38)
  • rust學(xué)習(xí)-泛型和trait

    Option,Vec,HashMapK, V,ResultT, E等,取函數(shù)以減少代碼重復(fù)的機(jī)制 兩個(gè)函數(shù),不同點(diǎn)只是名稱和簽名類型 重寫如下 為所有類型的結(jié)構(gòu)體提供方法 只為f32提供方法 方法使用了與結(jié)構(gòu)體定義中不同類型的泛型 Rust 實(shí)現(xiàn)了泛型,使得使用泛型類型參數(shù)的代碼相比使用具體類型并沒

    2024年02月17日
    瀏覽(15)
  • Rust語法: 枚舉,泛型,trait

    這是我學(xué)習(xí)Rust的筆記,本文適合于有一定高級(jí)語言基礎(chǔ)的開發(fā)者看不適合剛?cè)腴T編程的人,對于一些概念像枚舉,泛型等,不會(huì)再做解釋,只寫在Rust中怎么用。 枚舉的定義與賦值 枚舉的定義格式如下: enum 枚舉名{ 值1(附加類型), 值2(附加類型),… } 其中,關(guān)聯(lián)類型可以省去

    2024年02月13日
    瀏覽(23)
  • Rust-模式解構(gòu)

    Rust-模式解構(gòu)

    首先,我們看看使用match的最簡單的示例: 有些時(shí)候我們不想把每種情況一一列出,可以用一個(gè)下劃線來表達(dá)“除了列出來的那些之外的其他情況”: 下劃線還能用在模式匹配的各種地方,用來表示一個(gè)占位符,雖然匹配到了但是忽略它的值的情況: 下劃線表示省略一個(gè)元

    2024年01月17日
    瀏覽(21)
  • Rust---解構(gòu)(Destructuring)

    模式匹配是一種通用的編程概念,用于檢查數(shù)據(jù)結(jié)構(gòu)是否符合特定模式,并根據(jù)匹配結(jié)果執(zhí)行相應(yīng)的操作。而 解構(gòu)是模式匹配的一種應(yīng)用 ,用于從復(fù)雜的數(shù)據(jù)結(jié)構(gòu)中提取出需要的部分。 在 Rust 中,可以使用模式匹配和解構(gòu)來處理各種數(shù)據(jù)結(jié)構(gòu),包括元組、數(shù)組、結(jié)構(gòu)體、枚

    2024年04月10日
    瀏覽(21)
  • 30天拿下Rust之Trait

    概述 ????????在Rust中,Trait是一個(gè)核心概念,它允許我們定義類型應(yīng)該具有的行為。Trait類似于其他語言中的接口,但Rust的Trait更為強(qiáng)大和靈活。它不僅定義了一組方法,還允許我們指定方法的默認(rèn)實(shí)現(xiàn)、泛型約束和繼承。通過Trait,我們可以定義一組方法的簽名和關(guān)聯(lián)類

    2024年03月17日
    瀏覽(23)
  • Rust之泛型、trait與生命周期

    泛型是具體類型或其他屬性的抽象替代。在編寫代碼時(shí),可以直接描述泛型的行為,或者它與其他泛型產(chǎn)生的聯(lián)系,而無須知曉它在編譯和運(yùn)行代碼時(shí)采用的具體類型。 們可以在聲明函數(shù)簽名或結(jié)構(gòu)體等元素時(shí)使用泛型,并在隨后搭配不同的具體類型來使用這些元素。 當(dāng)使

    2024年02月13日
    瀏覽(25)
  • Rust 基礎(chǔ)入門 —— 變量綁定與解構(gòu)

    摸個(gè)筆記 首先討論的第一點(diǎn),就是對于傳統(tǒng)的開發(fā)者來說明:為什么要去用 這樣手動(dòng)設(shè)定的方式設(shè)定變量的可行性。 Course給出的解釋是——苦一苦開發(fā),樂一樂運(yùn)維。 好吧,讓我們理解,程序員的懶惰和貪婪是無止境的,我們想要一種類型自行推斷,但是性能提高、安全非

    2024年02月09日
    瀏覽(15)

覺得文章有用就打賞一下文章作者

支付寶掃一掃打賞

博客贊助

微信掃一掃打賞

請作者喝杯咖啡吧~博客贊助

支付寶掃一掃領(lǐng)取紅包,優(yōu)惠每天領(lǐng)

二維碼1

領(lǐng)取紅包

二維碼2

領(lǐng)紅包