rust學習19——高級特性

  • 沒有內存安全保證:Unsafe Rust谨究。
    • 和普通Rust一樣恩袱,提供了額外能力。
  • 存在原因:
    • 靜態(tài)分析時保守的:unsafe rust 我知道自己在做什么 并承擔風險胶哲。
    • 計算機本身就是不安全的畔塔,需要進行底層編程。

Unsafe超能力:

用unsafe關鍵字創(chuàng)建一個塊兒:

  • 解引用原始指針
  • 調用unsafe 函數(shù)或者方法
  • 訪問或者修改常量變量
  • 實現(xiàn)unsafe trait

注意:

  • 沒有關閉rust安全特性
  • 錯誤必須留在unsafe里
  • 盡可能隔離unsafe代碼鸯屿,對外提供安全api

解引用原始指針

  • 原始指針:
    • 可變的:*mut T
    • 不可變的:*const T
  • 與引用不同:
    • 允許通過同時具有不可變和可變指針或多個指向同一位置的可變指針來忽略借用規(guī)則澈吨。
    • 無法保證指向合理內存
    • 允許為null
    • 不實現(xiàn)任何自動清理
  • 放棄安全:換取性能或者一些其他語言和接口的硬件能力。


    image.png
  • 為什么要用碾盟?
    • 與C語言進行接口
    • 構造借用檢查器無法理解的安全抽象

調用unsafe函數(shù)或者方法

  • 定義前加上unsafe棚辽,調用前需要手動滿足一些條件
  • unsafe塊里調用

創(chuàng)建unsafe代碼的安全抽象

函數(shù)包含unsafe并不一定將整個函數(shù)標記為unsafe。
將unsafe代碼塊包裹在函數(shù)中是常見抽象冰肴。


image.png

使用extern函數(shù)調用代碼

  • extern默認就是不安全的
  • 簡化創(chuàng)建和使用外部函數(shù)接口的過程屈藐。
  • 允許其他編程語言調用本語言函數(shù)。
  • 應用二進制接口熙尉,匯編層面接口联逻。
  • C ABI最常見ABI遵循C語言:


從其他語言調用Rust接口

  • 可以使用extern創(chuàng)建接口,其他語言可以調用Rust函數(shù)
  • 在fn前添加extern并制定ABI
  • 需要添加#[no_mangle]注解检痰,避免Rust編譯時改變其名稱


訪問或者修改一個可變靜態(tài)變量

  • 支持全局變量:在rust里叫做靜態(tài)變量

靜態(tài)變量:

  • 靜態(tài)變量和常量類似
  • SCREAMING_SNAKE_CASE
  • 必須標注類型
  • 不需要標明聲明周期
  • 訪問不可靜態(tài)變量是安全的

常量和不可變靜態(tài)變量的區(qū)別

  • 靜態(tài)變量:

    • 有固定的內存地址包归,使用他的值總會放問同樣的數(shù)據(jù)。
    • 可變的:訪問和修改是unsafe的:


  • 常量:允許使用他們的時候對數(shù)據(jù)進行復制铅歼。

實現(xiàn)不安全的trait

  • 當某個trait中存在一個方法擁有編譯器無法校驗的不安全因素的時候公壤,就稱這個trait是不安全的。
  • 在trait前加unsafe:


何時使用unsafe代碼

  • 編譯器無法保證內存安全
  • 有充分理由
  • 顯示標記unsafe椎椰,快速定位問題

高級Trait

在Trait定義中使用關聯(lián)類型來指定占位類型

  • 關聯(lián)類型:Trait中類型的占位符厦幅,用在方法簽名中
    • 可以定義出包含某些類型的Trait,而在實現(xiàn)前無需知道這些類型是什么:


和泛型的區(qū)別

泛型:

  • 實現(xiàn)Trait時需要標注類型
  • 可以實現(xiàn)多次Trait(不同泛型參數(shù))



關聯(lián)類型:

  • 無需標注類型
  • 無法為單個類型多次實現(xiàn)某個Trait


默認泛型參數(shù)和運算符的重載

  • 指定默認泛型具體類型
  • <T = u32>
  • 常用于運算符重載
  • Rust不允許創(chuàng)建自己的運算符和重載任意運算符
  • 但是可以重載std:ops列舉出來的一部分運算符



    原來:



運用場景
  • 擴展一個類型而不破壞現(xiàn)有代碼
  • 允許在大部分用戶都不需要的特定場景下進行自定義

完全限定語法(fully qualified syntax)



指定對應的triat慨飘,然后傳入引用确憨。
但是上面的例子得以實現(xiàn)時因為fly的參數(shù)是self,但是如果沒有參數(shù)瓤的,怎么能調用其他trait的方法休弃?
這個時候就用到了完全限定語法: <Type as Trait>::function(xx, xxx);


使用supertrait來調用其他trait

  • 被依賴的trait也被實現(xiàn)
  • 被依賴的trait就是當前trait的supertriat



使用newtype模式在外部類型上實現(xiàn)外部trait

  • 孤兒規(guī)則:定義在本地包,才能實現(xiàn)trait
  • 利用newtype繞過該規(guī)則:tuple struct



    trait和vec都在外部圈膏,但是我們要為vec實現(xiàn)trait塔猾,實際上就是創(chuàng)建了一個新的struct來包了一層對應的類型。

高級類型

使用newtype模式實現(xiàn)類型安全和抽象

newtype可以:

  • 用來靜態(tài)保證各種值不被混淆
  • 為類型的某些細節(jié)提供抽象能力
  • 通過輕量級的封裝來隱藏內部實現(xiàn)細節(jié)

使用類型別名來創(chuàng)建同義詞

  • rust提供了類型別名功能:type關鍵字稽坤,并非獨立類型桥帆。
  • 主要用來減少代碼字符重復医增。




Never類型

  • 有一個名為!的特殊類型:
    • 它沒有任何值老虫,行話成為空類型
    • 不返回值的函數(shù)充當返回類型



      不寫返回值不代表沒有返回值,所以報錯茫多。
      Never類型可以強制轉化為其他類型:



      panic!也是never祈匙。
      無限循環(huán)也是never。

動態(tài)大小和Sized Trait

  • Rust需要在編譯時天揖,確定為一個特定類型的值分配多少空間夺欲。
  • 動態(tài)大小類型(DST):編寫代碼是使用只有在運行才能確定大小的值。
  • str是動態(tài)大小類型(不是&str):運行時才能確定長度:


Rust使用動態(tài)大小類型的通用方式

  • 附帶一些元數(shù)據(jù)來存儲動態(tài)信息的大小今膊。
    • 使用動態(tài)大小類型時總會把它的值放在某種指針后邊

另一種動態(tài)大小的類型:Trait

  • 每個trait都是一個動態(tài)大小的類型些阅,通過名稱進行引用。
  • 為了將trait用作trait對象斑唬,必須把它放置在某種指針之后市埋。


Sized Trait

來確定一個類型的大小是否在編譯時已知。

  • 編譯時計算出大小的類型會自動實現(xiàn)該trait
  • Rust還會為每一個泛型函數(shù)隱式的添加sized約束



    泛型函數(shù)只能被用于編譯時已經(jīng)知道大小的類型恕刘,但是特殊語法可以解除這一限制:

?Sized Trait約束

高級函數(shù)和閉包

函數(shù)指針

  • 可以將函數(shù)傳遞給其他函數(shù)
  • 函數(shù)在傳遞的過程中被強制轉化為fn類型
  • fn類型就是函數(shù)指針(function pointer)


函數(shù)指針和閉包的不同

  • fn是一個類型缤谎,不是一個trait:可以指定fn為參數(shù),而不用以Fn Trait為約束的泛型參數(shù)
  • 函數(shù)指針實現(xiàn)了全部3種閉包的trait(Fn FnMut FnOnce):總是可以把一個函數(shù)指針作為參數(shù)傳遞給一個接收閉包的函數(shù)
  • 所以褐着,傾向于搭配閉包Trait的泛型來編寫函數(shù):可以同時接收閉包和普通函數(shù)
  • 某些場景只想接收fn 而不想接收閉包:和其他語言交互



返回閉包

  • 閉包使用trait表示坷澡,無法直接返回一個閉包,可以將實現(xiàn)了該trait的具體類型作為返回值:


  • 相關特性的集合稱謂
    • 使用macro_rules!來構建聲明宏
    • 3種過程宏
      • 定義#[derive]宏含蓉,用于struct或者enum频敛,可為其指定隨derive屬性添加的代碼
      • 類似屬性的宏,在任何條目上添加自定義屬性
      • 類似函數(shù)的宏馅扣,看起來像函數(shù)調用斟赚,對其指定為參數(shù)的token進行操作

函數(shù)和宏的差別

  • 本質上,宏是用來編寫可以生成其他代碼的代碼(元編程岂嗓,metaprogramming)
  • 函數(shù)在定義簽名時汁展,必須聲明參數(shù)的個數(shù)和類型,宏可處理可變參數(shù)
  • 編譯器會在解釋代碼前厌殉,把宏展開
  • 宏的定義比函數(shù)復雜得多食绿,難以閱讀、理解公罕、維護
  • 在某個文件調用宏時器紧,必須提前定義宏或將宏引入當前作用域
  • 函數(shù)可以在任何位置定義并在任何位置調用

macro_rules! 聲明宏

  • Rust最常見的宏形式:聲明宏
    • 類似match的模式匹配
    • 需要使用macro_rules!

例子:


基于屬性來生成代碼的過程宏

  • 像函數(shù):
    • 接受一段rust代碼
    • 生成另外一些rust代碼為結果
  • 三種過程宏:
    • 自定義派生
    • 屬性宏
    • 函數(shù)宏
  • 創(chuàng)建過程宏時:
    • 宏定義必須單獨放在他們自己的包中,并使用特殊的包類型


自定義derive宏

  • 需求:
    • 創(chuàng)建一個hello_macro包楼眷,定義一個擁有關聯(lián)函數(shù)hello_macro的HelloMacro trait
    • 我們提供一個能夠自動實現(xiàn)trait的過程宏
    • 在他們上標明#[derive(HelloMacro)]铲汪,進而得到hello_macro的默認實現(xiàn)熊尉。
      一個trait往往需要默認實現(xiàn),如果我有9個struct都需要使用一個trait掌腰,那么我的默認實現(xiàn)可能就要寫9次狰住,而往往默認實現(xiàn)都非常的相似,我們不想寫這么多次齿梁,那么怎么辦催植?
      首先我們先創(chuàng)建了一個工作空間,底下有3個項目:
  • hello_macro
  • hello_macro_derive (過程宏)
  • hell_macro的使用方:Pancakes


hello_macro:


Pancakes希望最終能寫成:


如果沒有hello_macro_derive勺择,它只能寫成:



就得寫默認實現(xiàn)创南。

那么hello_macro_derive怎么實現(xiàn):
他的依賴:


  • syn:rust代碼變成ast
  • quote:將ast還原為字符串
    固定寫法:



    主要是impl_hello_macro:



    stringify!:將表達式變成字面字符串:比如stringify!(1 + 2) 輸出 "1+2";

類似屬性的宏

  • 屬性宏和自定義derive宏類似
    • 允許創(chuàng)建新的屬性
    • 但不是為derive屬性生成代碼
  • 屬性宏更靈活:運用在任何條目


類似函數(shù)的宏

  • 類似函數(shù)調用的宏,但是比普通函數(shù)更加靈活
  • 可以接收TokenStream作為參數(shù)
  • 可以操作TokenStream


?著作權歸作者所有,轉載或內容合作請聯(lián)系作者
  • 序言:七十年代末省核,一起剝皮案震驚了整個濱河市稿辙,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌气忠,老刑警劉巖邻储,帶你破解...
    沈念sama閱讀 219,270評論 6 508
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件笔刹,死亡現(xiàn)場離奇詭異,居然都是意外死亡舌菜,警方通過查閱死者的電腦和手機,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,489評論 3 395
  • 文/潘曉璐 我一進店門日月,熙熙樓的掌柜王于貴愁眉苦臉地迎上來袱瓮,“玉大人尺借,你說我怎么就攤上這事【猓” “怎么了燎斩?”我有些...
    開封第一講書人閱讀 165,630評論 0 356
  • 文/不壞的土叔 我叫張陵蜂绎,是天一觀的道長。 經(jīng)常有香客問我怪瓶,道長践美,這世上最難降的妖魔是什么找岖? 我笑而不...
    開封第一講書人閱讀 58,906評論 1 295
  • 正文 為了忘掉前任许布,我火速辦了婚禮绎晃,結果婚禮上,老公的妹妹穿的比我還像新娘。我一直安慰自己股囊,他們只是感情好,可當我...
    茶點故事閱讀 67,928評論 6 392
  • 文/花漫 我一把揭開白布夺刑。 她就那樣靜靜地躺著,像睡著了一般耘斩。 火紅的嫁衣襯著肌膚如雪坞笙。 梳的紋絲不亂的頭發(fā)上荚虚,一...
    開封第一講書人閱讀 51,718評論 1 305
  • 那天曲管,我揣著相機與錄音,去河邊找鬼腊徙。 笑死撬腾,一個胖子當著我的面吹牛,可吹牛的內容都是我干的胰默。 我是一名探鬼主播漓踢,決...
    沈念sama閱讀 40,442評論 3 420
  • 文/蒼蘭香墨 我猛地睜開眼喧半,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了取具?” 一聲冷哼從身側響起扁耐,我...
    開封第一講書人閱讀 39,345評論 0 276
  • 序言:老撾萬榮一對情侶失蹤婉称,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后榨乎,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體瘫筐,經(jīng)...
    沈念sama閱讀 45,802評論 1 317
  • 正文 獨居荒郊野嶺守林人離奇死亡策肝,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 37,984評論 3 337
  • 正文 我和宋清朗相戀三年之众,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片缀蹄。...
    茶點故事閱讀 40,117評論 1 351
  • 序言:一個原本活蹦亂跳的男人離奇死亡缺前,死狀恐怖,靈堂內的尸體忽然破棺而出拯刁,到底是詐尸還是另有隱情逝段,我是刑警寧澤,帶...
    沈念sama閱讀 35,810評論 5 346
  • 正文 年R本政府宣布帚桩,位于F島的核電站朗儒,受9級特大地震影響参淹,放射性物質發(fā)生泄漏乏悄。R本人自食惡果不足惜檩小,卻給世界環(huán)境...
    茶點故事閱讀 41,462評論 3 331
  • 文/蒙蒙 一筐付、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧较解,春花似錦、人聲如沸奸焙。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,011評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽嫂拴。三九已至,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間灶伊,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 33,139評論 1 272
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人狸页。 一個月前我還...
    沈念sama閱讀 48,377評論 3 373
  • 正文 我出身青樓,卻偏偏與公主長得像,于是被迫代替她去往敵國和親窃页。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 45,060評論 2 355

推薦閱讀更多精彩內容