1. <strong id="7actg"></strong>
    2. <table id="7actg"></table>

    3. <address id="7actg"></address>
      <address id="7actg"></address>
      1. <object id="7actg"><tt id="7actg"></tt></object>

        Rust 勸退系列 05:復(fù)合數(shù)據(jù)類型

        共 5771字,需瀏覽 12分鐘

         ·

        2021-05-09 05:40

        閱讀本文大概需要 8 分鐘。

        大家好,我是站長(zhǎng) polarisxu。

        這是 Rust 勸退系列的第 5 個(gè)教程,探討 Rust 中的復(fù)合數(shù)據(jù)類型(Compound types)。Rust 中有兩種原生的復(fù)合類型:元組(tuple)和數(shù)組(array),順帶介紹切片。

        01 元組類型

        Go 語言沒有元組類型,但多返回值有點(diǎn)類似元組(但還是有區(qū)別的哦)。Python 中有元組類型,因此如果你熟悉 Python,對(duì)元組應(yīng)該很熟悉。

        什么是元組類型?

        元組是一個(gè)可以包含各種類型的值的組合。元組是一個(gè)將多個(gè)其他類型的值組合進(jìn)一個(gè)復(fù)合類型的主要方式。元組長(zhǎng)度固定:一旦聲明,其長(zhǎng)度無法增大或縮小。元組的類型由各組成元素類型的序列定義。

        元組通過小括號(hào)定義,里面的元素通過逗號(hào)分隔,例如:

        (23.227'a');

        這個(gè)字面值元組的類型是:(f64, i32, char),即對(duì)應(yīng)每個(gè)元素的默認(rèn)類型。因此,我們可以通過 let 將這個(gè)元組綁定到變量上,Rust 會(huì)進(jìn)行類型推斷:

        let tup = (23.227'a');

        在 VSCode 中可以看到 tup 的類型就是:(f64, i32, char)。同樣地,我們也可以為 tup 使用類型注解:

        let tup: (f32i8char) = (23.227'a');

        因?yàn)樵M是多個(gè)類型的集合,對(duì)元組中的類型沒有限制。因此,可以嵌套。比如:

        (2, (2.1'a'), false);

        不過建議別嵌套太多,否則可讀性太差。

        如何訪問元組元素呢?

        上面說,Go 語言中函數(shù)多返回值類似元組,在接收多返回值時(shí),通過多個(gè)變量接收,比如:

        // Go 語言
        f, err := os.Open("abc.txt")

        在 Rust 中,可以解構(gòu)元組(這也叫模式匹配解構(gòu)):

        let tup = (23.227'a');
        let (x, y, z) = tup; // 注意:需要小括號(hào)

        和 Go 語言一樣,如果某個(gè)元素我們不關(guān)心,可以放入垃圾桶(_):

        let tup = (23.227'a');
        let (x, _, z) = tup; // 注意:需要小括號(hào)

        Rust 中變量定義未使用,不會(huì)像 Go 一樣報(bào)錯(cuò),但會(huì)警告!

        除了模式匹配解構(gòu),還可以使用類似訪問數(shù)組元素的方式訪問元組元素,只不過不是用[],而是用 . 加索引的方式(索引也是從 0 開始):

        let tup = (23.227'a');
        println!("{}", tup.1); // 輸出:27

        特殊的元組

        當(dāng)元組中只有一個(gè)元素時(shí)(即元組長(zhǎng)度是 1),唯一的元素后面必須加上逗號(hào):

        let tup = (2,); // 逗號(hào)不能少,否則會(huì)提示你,單個(gè)值應(yīng)該去掉小括號(hào)。這是避免將小括號(hào)當(dāng)做計(jì)算的優(yōu)先級(jí)

        自然,模式匹配解構(gòu)元組時(shí),也必須有逗號(hào)。

        如果元組沒有元素呢?即空元組??聪旅娴拇a:

        fn main() {
            let result = test_tuple();
            println!("{:?}", result);
        }

        fn test_tuple() {
            println!("test empty tuple");
        }

        你猜打印 result 是啥?

        擦,竟然是 (),即空元組。而且 Rust 給它專門取了一個(gè)名字:?jiǎn)卧愋停╱nit type),也就是說,() 叫單元類型,它有一個(gè)唯一值:空元組 ()。而且,因?yàn)闆]有任何元素,Rust 將其歸為變量類型。

        還嫌 Rust 不夠復(fù)雜嗎?就叫空元組不行嗎?非得搞一個(gè)單元類型,這么奇怪的類型。。。

        為了避免復(fù)雜性,我覺得大家將其理解為空元組即可。至于為什么這里會(huì)返回空元組,在函數(shù)部分會(huì)講解。

        注意:() 是不占空間的,這和 Go 中的空結(jié)構(gòu)體類似。

        02 數(shù)組

        Rust 中的數(shù)組和 Go 中的類似,是不可變的,由元素類型和長(zhǎng)度確定,且長(zhǎng)度必須是編譯期常量。Rust 中,數(shù)組類型標(biāo)記為 [T; size]。數(shù)組字面值使用 [] 表示:

        let a = [1234];

        同樣會(huì)進(jìn)行類型推斷(包括長(zhǎng)度)(這里推斷出 a 的類型是 [i32; 4]),也可以顯示進(jìn)行類型注解:

        let a: [i84] = [1234];

        相比較而言,Rust 創(chuàng)建數(shù)組比 Go 簡(jiǎn)單,它和 PHP 這樣的動(dòng)態(tài)語言類似。在 Go 中一般這樣創(chuàng)建數(shù)組:

        // Go 語言
        a := [...]int{1234}

        也就是說,Go 中創(chuàng)建數(shù)組是,類型信息不能少,沒法跟 Rust 一樣進(jìn)行類型推斷。

        除了上面的初始化方法,Rust 中還可以這樣簡(jiǎn)單的初始化:

        let a = [-14]; // 4 個(gè)元素都是 -1

        Rust 變量必須初始化后才能使用,而 Go 語言中,變量會(huì)有默認(rèn)值。所以,Go 中可以簡(jiǎn)單的定義一個(gè)數(shù)組,然后使用默認(rèn)的初始值。如:

        // Go 語言
        var a [4]int  // a 的值是:[0 0 0 0]

        此外,Rust 中數(shù)組總是分配在棧中的,因此可以認(rèn)為數(shù)組是「值類型」,和 Go 一樣,我們不應(yīng)該直接傳遞數(shù)組,而應(yīng)該和 Go 一樣,使用 slice。

        03 切片(slice)

        Rust 中的切片和 Go 中的切片意思一樣,表示對(duì)數(shù)組部分元素的引用。但和 Go 不同的是,Rust 的切片沒有容量的概念,只有一個(gè)指向數(shù)據(jù)的指針和切片的長(zhǎng)度。Rust 中切片的類型標(biāo)記為 &[T],即對(duì)數(shù)組進(jìn)行引用(&)就是切片。

        Go 語言中有直接創(chuàng)建切片的語法(比如 make),但 Rust 中沒有,它必須依賴數(shù)組或 Vec(以后講解),通過引用來創(chuàng)建。

        let xs = [12345];
        let slice = &xs;

        既然切片是數(shù)組元素的片段引用,那如何引用部分片段呢?

        在 Go 中是這么做的:

        var arr = [...]int{1234}
        var slice1 = arr[:]   // 結(jié)果是 [1 2 3 4],全部元素
        var slice2 = arr[1:3]  // 結(jié)果是 [2 3]
        var slice3 = arr[:3]  // 結(jié)果是 [1 2 3]
        var slice4 = arr[1:]  // 結(jié)果是 [2 3 4]

        而在 Rust 中是這么做的:(結(jié)果和上面一樣)

        let arr = [1234];
        let slice1 = &arr[..];
        let slice2 = &arr[1..3];
        let slice3 = &arr[..3];
        let slice4 = &arr[1..];

        看到不同了嗎?

        • Rust 中生成切片,需要引用(&);
        • Go 中使用 : 來引用片段;而 Rust 使用 ..;

        相同的點(diǎn)是,都可以省略起始或終止位置,或都省略。

        關(guān)于 .. 以后還會(huì)講到

        切片類型的方法(也適用于數(shù)組)

        在 Rust 中,一切類型都有實(shí)現(xiàn)一些 trait,包括上一節(jié)的標(biāo)量類型(用面向?qū)ο髞碇v,一切皆對(duì)象)?,F(xiàn)在先不探討 trait,著重看看 len 方法。具體參考標(biāo)準(zhǔn)庫文檔:https://doc.rust-lang.org/std/primitive.slice.html。

        1)len:計(jì)算長(zhǎng)度

        數(shù)組或切片有一個(gè) len() 方法可以計(jì)算長(zhǎng)度。

        pub const fn len(&self) -> usize

        // 具體使用
        let arr = [123];
        assert_eq!(arr.len(), 3);  // assert_eq 和 println 一樣,是一個(gè)宏,用來斷言

        而 Go 語言中,使用 len(arr) 的形式,len 是內(nèi)置函數(shù)。

        不過,關(guān)于 len 還有一些細(xì)小的點(diǎn)??聪旅娴?Go 代碼,你覺得有問題嗎?

        var arr = [...]int{1234}
        var slice = arr[:]

        var arr2 [len(arr)]int
        var arr3 [len(slice)]int

        在 Go  中,要求數(shù)組長(zhǎng)度要求是編譯期常量。len(arr) 是編譯期常量,而 len(slice) 卻不是,因?yàn)?slice 的長(zhǎng)度是可變的。所以,以上代碼 arr2 正確,arr3 編譯錯(cuò)誤。

        那 Rust 中是怎么樣的呢?

        let arr = [1234];
        let slice = &arr[..];

        let arr2 = [0;arr.len()];
        let arr3 = [0;slice.len()];

        arr2 和 arr3 都編譯錯(cuò)誤。arr3 錯(cuò)誤可以理解,為什么 arr2 也不行呢?

        根據(jù)編譯器提示,怎么修改 arr2 就可以了:

        const ARR:[i324] = [1234];
        let arr2 = [0; ARR.len()];

        也就是說必須是數(shù)組常量。。。但數(shù)組本身不就是不可變的嗎?非得定義成常量,多此一舉?據(jù)說,Rust 有可能將數(shù)組改成可變的。。。有了切片,為啥還要把數(shù)組搞這么復(fù)雜?!

        2)其他方法

        • is_empty:判斷數(shù)組或切片是否為空
        • first:獲取第一個(gè)元素
        • last:獲取最后一個(gè)元素
        • 。。。

        first 和 last 有什么用?為啥不直接通過下標(biāo)獲???

        • last 的存在,使得我們不需要先調(diào)用 len 獲取長(zhǎng)度來間接獲取最后一個(gè)元素。
        • 而 first 的存在,使得我們不需要先判斷是否為空。

        不過,因?yàn)榇嬖跀?shù)組或切片為空的情況,因此 first 和 last 返回的都是 Opiton 類型。關(guān)于該類型后續(xù)再講。

        04 小結(jié)

        我們用兩篇講解了 Rust 中的數(shù)據(jù)類型,同時(shí)和 Go 的數(shù)據(jù)類型進(jìn)行了對(duì)比。但 Rust 中的數(shù)據(jù)類型不止這些,還有其他類型,我們以后再講,包括通過標(biāo)準(zhǔn)庫定義的數(shù)據(jù)類型。

        再強(qiáng)調(diào)一次,本系列教程的目標(biāo)是讓大家學(xué)習(xí)盡可能不被勸退,因此有些特別復(fù)雜但我認(rèn)為可以不用的,就不會(huì)介紹。關(guān)于 Rust 中的 primitive type 可以在標(biāo)準(zhǔn)庫文檔找到,以及每個(gè)類型的方法。https://doc.rust-lang.org/std/index.html#primitives。




        往期推薦


        我是 polarisxu,北大碩士畢業(yè),曾在 360 等知名互聯(lián)網(wǎng)公司工作,10多年技術(shù)研發(fā)與架構(gòu)經(jīng)驗(yàn)!2012 年接觸 Go 語言并創(chuàng)建了 Go 語言中文網(wǎng)!著有《Go語言編程之旅》、開源圖書《Go語言標(biāo)準(zhǔn)庫》等。


        堅(jiān)持輸出技術(shù)(包括 Go、Rust 等技術(shù))、職場(chǎng)心得和創(chuàng)業(yè)感悟!歡迎關(guān)注「polarisxu」一起成長(zhǎng)!也歡迎加我微信好友交流:gopherstudio

        瀏覽 120
        點(diǎn)贊
        評(píng)論
        收藏
        分享

        手機(jī)掃一掃分享

        分享
        舉報(bào)
        評(píng)論
        圖片
        表情
        推薦
        點(diǎn)贊
        評(píng)論
        收藏
        分享

        手機(jī)掃一掃分享

        分享
        舉報(bào)
        1. <strong id="7actg"></strong>
        2. <table id="7actg"></table>

        3. <address id="7actg"></address>
          <address id="7actg"></address>
          1. <object id="7actg"><tt id="7actg"></tt></object>
            色婷婷国产成人精品视频 | 成人毛片100免费观看 | 男人添女荫道口喷水视频 | 黄色成人视频免费看 | 天天撸在线| 凹凸日日摸日日碰夜夜爽孕妇 | 女人ⅹxx免费视频 | 麻豆国产一区 | 91探花国产综合在线精品最新章节 | 边做边爱免费观看 |