91在线观看视频-91在线观看视频-91在线观看免费视频-91在线观看免费-欧美第二页-欧美第1页

0
  • 聊天消息
  • 系統(tǒng)消息
  • 評論與回復(fù)
登錄后你可以
  • 下載海量資料
  • 學(xué)習(xí)在線課程
  • 觀看技術(shù)視頻
  • 寫文章/發(fā)帖/加入社區(qū)
會員中心
創(chuàng)作中心

完善資料讓更多小伙伴認識你,還能領(lǐng)取20積分哦,立即完善>

3天內(nèi)不再提示

Rust中GAT和高階類型

jf_wN0SrCdH ? 來源:Rust語言中文社區(qū) ? 作者:Rust語言中文社區(qū) ? 2022-11-07 10:21 ? 次閱讀
加入交流群
微信小助手二維碼

掃碼添加小助手

加入工程師交流群

05ad3ac8-5de9-11ed-a3b6-dac502259ad0.jpg

Rust在類型系統(tǒng)級別上與Haskell,Scala有許多相似之處。

兩者都有類型(type),泛型類型(generic types),關(guān)聯(lián)類型(associated types)和特質(zhì)/類型類(traits/type classes)(基本上是等效的)。

但是,Haskell有Rust缺乏的一個特性:高階類型(Higher Kinded Types), 也就是通常說的HKTs。

這不是Rust故意不添加,也不是Rust應(yīng)該填補的一些差距。其實這是Rust的一個有意的設(shè)計。

結(jié)果就是,到?jīng)]有GATs出現(xiàn)時,某些代碼無法真正在Rust中實現(xiàn)。

以Haskell中的Functor為例。Functor其實是對類型上實現(xiàn)的map的一個更加抽象的實現(xiàn),不關(guān)心具體類型的一個接口

比如,在Scala中,要實現(xiàn)一個map的Functor是這樣的:

importscala.language.higherKinds

traitFunctor[F[_]]{
defmap[A,B](fa:F[A])(f:A=>B):F[B]
}

如果你使用過Scala的集合api,這看起來應(yīng)該非常相似。所有集合都可以使用map。

List(1,2,3).map(_+1)
//List(2,3,4)

你可能要問,什么是高階類型啊.你可以先理解為: 高階類型是類型的類型。這是什么意思呢? 我以Scala里面的代碼來說明一下。

scala>traitMyList[A]{
defhead:A
deftail:MyList[A]
}

然后用:k命令看下是什么類型:

scala>:k-vMyList
MyList'skindisF[A]
*->*
Thisisatypeconstructor:a1st-order-kindedtype.

MyList[String]類型是一個一階類型(1st-order-kinded type);任何MyList的類型都是由A參數(shù)化的,可以將MyList看作是一個類型函數(shù),如A => MyList[A],因此給定一個類型A,我們可以創(chuàng)建一個新的類型MyList[A]。如果MyList是一階類型,那么什么是類型化類型呢?其實想想,什么是高階函數(shù)啊? 它不就是一個接受函數(shù)然后返回另外另一個函數(shù)的函數(shù)。同理可得,什么是高階類型呢? 它是由另一個類型參數(shù)化的類型。我再寫一個簡單的例子。

scala>traitFoo[F[_]]:k-vFoo
Foo'skindisX[F[A]]
(*->*)->*
Thisisatypeconstructorthattakestypeconstructor(s):ahigher-kindedtype.

這里的Foo就是一個高階類型。它是一個類型構(gòu)造函數(shù),參數(shù)也是一個類型構(gòu)造函數(shù)。為了說清楚這點,我再寫一個例子.我寫一個trait,里面有一個leftFold的方法。

scala>traitFoldable[F[_]]{
|defleftFold[A,B](ob:F[A])(zero:B)(fn:(B,A)=>B):B
|}

然后呢,我再實現(xiàn)一個listFoldable, 這是最常見的吧。

scala>implicitvallistFoldable:Foldable[List]=newFoldable[List]{
|defleftFold[A,B](ob:List[A])(zero:B)(fn:(B,A)=>B):B={
|ob.foldLeft(zero)(fn)
|}
|}

上面我定義了一個適用于任何List類型的Foldable對象。leftFold方法將取A并使用A構(gòu)造List[A]。

一種更好的寫法:

scala>importscala.language.implicitConversions
importscala.language.implicitConversions

scala>implicitclassListFoldableOpt[A](list:List[A])(implicitfold:Foldable[List]){
|defleftFold[B](zero:B)(fn:(B,A)=>B):B=
|fold.leftFold(list)(zero)(fn)
|}

scala>List(1,2,3).leftFold(0)(_+_)//6

這里先收一下,回到Rust中。

Rust中的很多不同結(jié)構(gòu)都實現(xiàn)了map函數(shù),比如: Option, Result, Iterator, and Future.

但是, 在Rust里面,還不能編寫可以給多種類型實現(xiàn)的通用Functortrait, 就像我剛才上面寫的trait Functor[F[_]]。通常呢 在Rust里面是單個類型單獨去實現(xiàn)map。例如,我這里自己寫了一個MyOption和MyResult枚舉類, 并實現(xiàn)了map方法.

#[derive(Debug,PartialEq)]
enumMyOption{
Some(A),
None,
}

implMyOption{
fnmapB,B>(self,f:F)->MyOption{
matchself{
MyOption::Some(a)=>MyOption::Some(f(a)),
MyOption::None=>MyOption::None,
}
}
}

#[test]
fntest_option_map(){
assert_eq!(MyOption::Some(5).map(|x|x+1),MyOption::Some(6));
assert_eq!(MyOption::None.map(|x:i32|x+1),MyOption::None);
}

#[derive(Debug,PartialEq)]
enumMyResult{
Ok(A),
Err(E),
}

implMyResult{
fnmapB,B>(self,f:F)->MyResult{
matchself{
MyResult::Ok(a)=>MyResult::Ok(f(a)),
MyResult::Err(e)=>MyResult::Err(e),
}
}
}

#[test]
fntest_result_map(){
assert_eq!(MyResult::Ok(5).map(|x|x+1),MyResult::(6));
assert_eq!(MyResult::Err("hello").map(|x:i32|x+1),MyResult::Err("hello"));
}

上面的幾個例子都是直接在自己的結(jié)構(gòu)中定義的map方法。如果沒有GATs, 就不可能將map定義為一個trait的方法。這是為什么呢?下面是一個在Rust里面簡單的Functortrait實現(xiàn),以及Option的實現(xiàn).

traitNaiveFunctor{
typeT;
fnmap(self,f:F)->Self
where
F:FnMut(Self::T)->Self::T;
}

implNaiveFunctorforOption{
typeT=A;
fnmapA>(self,mutf:F)->Option{
matchself{
Some(a)=>Some(f(a)),
None=>None,
}
}
}

在上面的trait定義中,先給NaiveFunctor內(nèi)部的值定義了一個關(guān)聯(lián)類型T。給Optionimpl這個trait,T=A。這就是問題所在。Rust將T硬編碼為一種類型A,因為通常在map函數(shù)中,希望返回的類型是B,但在之前版本穩(wěn)定的Rust中,沒有辦法說"我想要一個既能與NaiveFunctor關(guān)聯(lián)的類型,又要求這個類型和關(guān)聯(lián)類型有一點不一樣。

這就是泛型關(guān)聯(lián)類型發(fā)揮作用的地方了。

多態(tài)Functor的實現(xiàn)

為了得到一個多態(tài)Functor.我想要的是:"我的類型最終應(yīng)該是我在其中包裹的類型".例如,對于Option,我想說的是"如果我有一個Option,那么它肯定包含一個A類型,但如果它包含一個B類型,它將是Option"

這里就需要使用泛型關(guān)聯(lián)類型.

traitFunctor{
typeUnwrapped;
typeWrapped:Functor;
fnmap(self,f:F)->Self::Wrapped
where
F:FnMut(Self::Unwrapped)->B;
}

說明下上面的寫法:

每個Functor都有一個關(guān)聯(lián)的Unwrapped類型.

還有另一個關(guān)聯(lián)類型Wrapped,它與Self類似,但有一個不同的包裝值

和前面例子一樣, map接受兩個參數(shù)的一個是:self和一個函數(shù)

函數(shù)形參將從當(dāng)前關(guān)聯(lián)的Unwrapped值映射到一個新的類型B

map的輸出是一個Wrapped

有點抽象。具體點現(xiàn)在看下Option類型是什么樣子的

implFunctorforOption{
typeUnwrapped=A;
typeWrapped=Option;

fnmapB,B>(self,mutf:F)->OptionwhereF:FnMut(A)->B{
matchself{
Some(x)=>Some(f(x)),
None=>None,
}
}
}

#[test]
fntest_option_map(){
assert_eq!(Some(5).map(|x|x+1),Some(6));
assert_eq!(None.map(|x:i32|x+1),None);
}

編譯通過,非常優(yōu)雅。

類型類

在Haskell和Scala中,其實是不需要這種泛型關(guān)聯(lián)類型的。事實上,Haskell中Functors不使用任何關(guān)聯(lián)類型。Haskell中Functor的類型類遠遠早于其他語言中關(guān)聯(lián)類型的出現(xiàn)。為了進行比較,先看看它是什么樣子。

classFunctorfwhere
map::(a->b)->fa->fb

instanceFunctorOptionwhere
mapfoption=
caseoptionof
Somex->Some(fx)
None->None
traitFunctor[F[_]]{
defmap[A,B](fa:F[A])(f:A=>B):F[B]
}

把它轉(zhuǎn)換成Rust就是如下:

traitHktFunctor{
fnmapB>(self:Self,f:F)->Self;
}

implHktFunctorforOption{
fnmapB>(self:Option,f:F)->Option{
matchself{
Some(a)=>Some(f(a)),
None=>None,
}
}
}

但是上面的代碼是編譯不通過的。因為我試圖給Self提供類型參數(shù)。但是在Rust中, 單獨一個Option不是一個類型. Option要成為一個類型,必須有一個類型參數(shù).比如: Option 是一個類型. Option卻不是.

相反,在Haskell中,Maybe Int是kind type的一種類型。Maybe是類型構(gòu)造函數(shù),類型為type -> type。但是出于創(chuàng)建類型類和實例的目的,可以將Maybe處理為具有自己的類型。Haskell中的Functor作用于type->type。

這就是我所說的"高階類型": 就是說我可以寫出擁有類型的類型(Kind)。

Pointer 的實現(xiàn)

Haskell中有一個有爭議的類型類叫做Pointed。之所以有爭議的,是因為它引入了一個類型類,但沒有與它相關(guān)的任何laws。我想在Rust中實現(xiàn)下Pointed。

什么是Pointed

Pointed的思想很簡單:將一個值包裝成一個類似Functor的東西。比如:在Option的情況下,它就用Some包裝它。在Result中,它使用Ok。對于Vec,它是一個單值向量。與Functor不同,這里是一個靜態(tài)方法,因為我們沒有現(xiàn)有的Point值要改。讓我們看看它在Rust中的實現(xiàn)。

traitPointed:Functor{
fnwrap(t:T)->Self::Wrapped;
}

implPointedforOption{
fnwrap(t:T)->Self::Wrapped{
Some(t)
}
}

這里需要注意的是: 我根本沒有在Option實現(xiàn)中使用A類型參數(shù)。

還有一點值得注意。調(diào)用wrap的結(jié)果返回的是Self::Wrapped。關(guān)于Self::Wrapped,到底是什么?從之前Functor的定義中,確切地知道一件事:Wrapped必須是一個Functor的。

本篇文章關(guān)于GATs就先聊到這里。感興趣的同學(xué)可以關(guān)注下公眾號。下篇再見。

審核編輯:湯梓紅

  • 函數(shù)
    +關(guān)注

    關(guān)注

    3

    文章

    4381

    瀏覽量

    64912
  • GAT
    GAT
    +關(guān)注

    關(guān)注

    0

    文章

    7

    瀏覽量

    6436
  • Rust
    +關(guān)注

    關(guān)注

    1

    文章

    234

    瀏覽量

    7105
收藏 人收藏
加入交流群
微信小助手二維碼

掃碼添加小助手

加入工程師交流群

    評論

    相關(guān)推薦
    熱點推薦

    如何在Rust中高效地操作文件

    ,本教程將介紹如何在Rust中高效地操作文件,并提供多個實際應(yīng)用示例。 文件讀取 Rust語言中操作文件的第一步就是文件讀取,使用Rust內(nèi)置的 std::fs::File 類型即可。
    的頭像 發(fā)表于 09-19 11:51 ?3017次閱讀

    Rust的From和Into trait的基礎(chǔ)使用方法和進階用法

    、可靠和安全的系統(tǒng)級應(yīng)用的首選語言。 Rust的From和Into是兩個重要的trait,它們可以幫助我們進行類型轉(zhuǎn)換。From trait允許我們從一個類型轉(zhuǎn)換到另一個
    的頭像 發(fā)表于 09-20 10:55 ?2181次閱讀

    如何在Rust讀寫文件

    見的內(nèi)存安全問題和數(shù)據(jù)競爭問題。 在Rust,讀寫文件是一項非常常見的任務(wù)。本教程將介紹如何在Rust讀寫文件,包括基礎(chǔ)用法和進階用法。 基礎(chǔ)用法 讀取文件內(nèi)容 使用 std::f
    的頭像 發(fā)表于 09-20 10:57 ?2581次閱讀

    Rust的多線程編程概念和使用方法

    Rust是一種強類型、高性能的系統(tǒng)編程語言,其官方文檔強調(diào)了Rust的標(biāo)準(zhǔn)庫具有良好的并發(fā)編程支持。Thread是Rust
    的頭像 發(fā)表于 09-20 11:15 ?1412次閱讀

    Windows -編程-數(shù)據(jù)類型

    Windows -編程-數(shù)據(jù)類型Rust 的每個值都有特定的數(shù)據(jù)類型,它告訴 Rust 指定了什么樣的數(shù)據(jù),以便它知道如何處理這些數(shù)據(jù)。我
    發(fā)表于 08-24 14:30

    RUST在嵌入式開發(fā)的應(yīng)用是什么

    Rust是一種編程語言,它使用戶能夠構(gòu)建可靠、高效的軟件,尤其是用于嵌入式開發(fā)的軟件。它的特點是:高性能:Rust具有驚人的速度和高內(nèi)存利用率。可靠性:在編譯過程可以消除內(nèi)存錯誤。生產(chǎn)效率:優(yōu)秀
    發(fā)表于 12-24 08:34

    Rust代碼中加載靜態(tài)庫時,出現(xiàn)錯誤 ` rust-lld: error: undefined symbol: malloc `怎么解決?

    時,出現(xiàn)錯誤 ` [i]rust-lld: error: undefined symbol: malloc `。如何將這些定義包含在我的靜態(tài)庫
    發(fā)表于 06-09 08:44

    GAT 聯(lián)柵晶體管

    GAT 聯(lián)柵晶體
    發(fā)表于 11-06 17:07 ?828次閱讀

    聯(lián)柵晶體管(GAT)是什么意思?

    聯(lián)柵晶體管(GAT)是什么意思?  聯(lián)柵晶體管是一種新型功率開關(guān)半導(dǎo)體器件,簡稱GATGAT是介于雙極型晶體管(BJT)和場效應(yīng)晶體管(FET)之間的特種器
    發(fā)表于 03-05 14:35 ?3048次閱讀

    Linux內(nèi)核整合對 Rust 的支持

    Linux Plumbers Conference 2022 大會上舉行了一個 Rust 相關(guān)的小型會議,該會議討論的大方向大致為:正在進行的使 Rust 成為一種合適的系統(tǒng)編程語言的工作,以及在主線 Linux 內(nèi)核整合對
    的頭像 發(fā)表于 09-19 11:06 ?1383次閱讀

    Rust原子類型和內(nèi)存排序

    原子類型在構(gòu)建無鎖數(shù)據(jù)結(jié)構(gòu),跨線程共享數(shù)據(jù),線程間同步等多線程并發(fā)編程場景起到至關(guān)重要的作用。本文將從Rust提供的原子類型和原子類型的內(nèi)
    的頭像 發(fā)表于 10-31 09:21 ?1203次閱讀

    什么是高階類型啊?如何去定義高階類型

    這不是Rust故意不添加,也不是Rust應(yīng)該填補的一些差距。 其實這是Rust的一個有意的設(shè)計。
    的頭像 發(fā)表于 11-07 10:20 ?1762次閱讀

    rust語言基礎(chǔ)學(xué)習(xí): Default trait

    Default trait 顧名思義是默認值,即Rust為特定類型實現(xiàn) Default 特性時,可以為該類型賦予了可選的默認值。
    的頭像 發(fā)表于 05-22 16:16 ?1551次閱讀

    rust語言基礎(chǔ)學(xué)習(xí): rust的錯誤處理

    錯誤是軟件不可避免的,所以 Rust 有一些處理出錯情況的特性。在許多情況下,Rust 要求你承認錯誤的可能性,并在你的代碼編譯前采取一些行動。
    的頭像 發(fā)表于 05-22 16:28 ?2539次閱讀

    RustPin/Unpin詳解

    對我來說,其中之一就是在Rust Pin/Unpin 。
    的頭像 發(fā)表于 07-20 11:00 ?1277次閱讀
    主站蜘蛛池模板: 日韩久久精品视频 | 男女性高爱潮免费的国产 | 毛片官网 | 人人插人人干 | 性生大片一级毛片免费观看 | 成人a毛片视频免费看 | 看片地址 | 狠狠色综合久久婷婷 | 种子天堂 | 成人午夜小视频手机在线看 | 国产成年网站v片在线观看 国产成人91青青草原精品 | 国产h在线观看 | 韩国黄色三级视频 | 成人涩涩网站 | 热99热| 黄色网址在线免费观看 | 国产午夜精品片一区二区三区 | 久久毛片视频 | 天天激情站| 天天翘夜夜洗澡天天做 | 亚洲电影免费 | 国产裸体美女视频全黄 | 四虎影院一区二区 | 伊人久久精品成人网 | 天天操精品 | 4hu影院最新地址www | 性满足久久久久久久久 | 五月婷亚洲 | 中文字幕导航 | 亚洲jizzjizz中国妇女 | 伊人不卡久久大香线蕉综合影院 | eeuss影院www影院夜场 | 国产一区二区三区美女图片 | 美女扒开尿口给男人看的让 | 国产好深好硬好爽我还要视频 | 日本高清视频色wwwwww色 | 亚洲成人网在线观看 | 久久99精品久久久久久野外 | 日产精品卡二卡三卡四卡乱码视频 | 日本成人福利视频 | 天天干天天干 |