學習Rust 結構體

安全劍客發表於2020-12-06
Rust 語言是一種高效、可靠的通用高階語言。其高效不僅限於開發效率,它的執行效率也是令人稱讚的,是一種少有的兼顧開發效率和執行效率的語言。

學習Rust 結構體學習Rust 結構體
Rust 中的結構體(Struct)與元組(Tuple)都可以將若干個型別不一定相同的資料捆綁在一起形成整體,但結構體的每個成員和其本身都有一個名字,這樣訪問它成員的時候就不用記住下標了。元組常用於非定義的多值傳遞,而結構體用於規範常用的資料結構。結構體的每個成員叫做"欄位"。

結構體定義

這是一個結構體定義:

struct Site {
    domain: String,
    name: String,
    nation: String,
    found: u32
}

注意:如果你常用 C/C++,請記住在 Rust 裡 struct 語句僅用來定義,不能宣告例項,結尾不需要 ; 符號,而且每個欄位定義之後用 , 分隔。

結構體例項

Rust 很多地方受 JavaScript 影響,在例項化結構體的時候用 JSON 物件的 key: value 語法來實現定義:

例項

let runoob = Site {
    domain: String::from("),
    name: String::from("RUNOOB"),
    nation: String::from("China"),
    found: 2013
};

如果你不瞭解 JSON 物件,你可以不用管它,記住格式就可以了:

結構體類名 {
    欄位名 : 欄位值,
    ...
}

這樣的好處是不僅使程式更加直觀,還不需要按照定義的順序來輸入成員的值。

如果正在例項化的結構體有欄位名稱和現存變數名稱一樣的,可以簡化書寫:

例項

let domain = String::from(");
let name = String::from("RUNOOB");
let runoob = Site {
    domain,  // 等同於 domain : domain,
    name,    // 等同於 name : name,
    nation: String::from("China"),
    traffic: 2013
};

有這樣一種情況:你想要新建一個結構體的例項,其中大部分屬性需要被設定成與現存的一個結構體屬性一樣,僅需更改其中的一兩個欄位的值,可以使用結構體更新語法:

let site = Site {
    domain: String::from("),
    name: String::from("RUNOOB"),
    ..runoob
};

注意:..runoob 後面不可以有逗號。這種語法不允許一成不變的複製另一個結構體例項,意思就是說至少重新設定一個欄位的值才能引用其他例項的值。

元組結構體

有一種更簡單的定義和使用結構體的方式:元組結構體。

元組結構體是一種形式是元組的結構體。

與元組的區別是它有名字和固定的型別格式。它存在的意義是為了處理那些需要定義型別(經常使用)又不想太複雜的簡單資料:

struct Color(u8, u8, u8);
struct Point(f64, f64);
let black = Color(0, 0, 0);
let origin = Point(0.0, 0.0);

"顏色"和"點座標"是常用的兩種資料型別,但如果例項化時寫個大括號再寫上兩個名字就為了可讀性犧牲了便捷性,Rust 不會遺留這個問題。元組結構體物件的使用方式和元組一樣,透過 . 和下標來進行訪問:

例項

fn main() {
    struct Color(u8, u8, u8);
    struct Point(f64, f64);
    let black = Color(0, 0, 0);
    let origin = Point(0.0, 0.0);
    println!("black = ({}, {}, {})", black.0, black.1, black.2);
    println!("origin = ({}, {})", origin.0, origin.1);
}

執行結果:

black = (0, 0, 0)
origin = (0, 0)
結構體所有權

結構體必須掌握欄位值所有權,因為結構體失效的時候會釋放所有欄位。

這就是為什麼本章的案例中使用了 String 型別而不使用 &str 的原因。

但這不意味著結構體中不定義引用型欄位,這需要透過"生命週期"機制來實現。

但現在還難以說明"生命週期"概念,所以只能在後面章節說明。

輸出結構體
除錯中,完整地顯示出一個結構體例項是非常有用的。但如果我們手動的書寫一個格式會非常的不方便。所以 Rust 提供了一個方便地輸出一整個結構體的方法:

例項

#[derive(Debug)]
struct Rectangle {
    width: u32,
    height: u32,
}
fn main() {
    let rect1 = Rectangle { width: 30, height: 50 };
    println!("rect1 is {:?}", rect1);
}

如第一行所示:一定要匯入除錯庫 #[derive(Debug)] ,之後在 println 和 print 宏中就可以用 {:?} 佔位符輸出一整個結構體:

rect1 is Rectangle { width: 30, height: 50 }

如果屬性較多的話可以使用另一個佔位符 {:#?} 。

輸出結果:

rect1 is Rectangle {
    width: 30,
    height: 50
}
結構體方法

方法(Method)和函式(Function)類似,只不過它是用來操作結構體例項的。

如果你學習過一些物件導向的語言,那你一定很清楚函式一般放在類定義裡並在函式中用 this 表示所操作的例項。

Rust 語言不是物件導向的,從它所有權機制的創新可以看出這一點。但是物件導向的珍貴思想可以在 Rust 實現。

結構體方法的第一個引數必須是 &self,不需宣告型別,因為 self 不是一種風格而是關鍵字。

計算一個矩形的面積:

例項

struct Rectangle {
    width: u32,
    height: u32,
}
   
impl Rectangle {
    fn area(&self) -> u32 {
        self.width * self.height
    }
}
fn main() {
    let rect1 = Rectangle { width: 30, height: 50 };
    println!("rect1's area is {}", rect1.area());
}

輸出結果:

rect1's area is 1500

請注意,在呼叫結構體方法的時候不需要填寫 self ,這是出於對使用方便性的考慮。

一個多引數的例子:

例項

struct Rectangle {
    width: u32,
    height: u32,
}
impl Rectangle {
    fn area(&self) -> u32 {
        self.width * self.height
    }
    fn wider(&self, rect: &Rectangle) -> bool {
        self.width > rect.width
    }
}
fn main() {
    let rect1 = Rectangle { width: 30, height: 50 };
    let rect2 = Rectangle { width: 40, height: 20 };
    println!("{}", rect1.wider(&rect2));
}

執行結果:

false

這個程式計算 rect1 是否比 rect2 更寬。

結構體關聯函式

之所以"結構體方法"不叫"結構體函式"是因為"函式"這個名字留給了這種函式:它在 impl 塊中卻沒有 &self 引數。

這種函式不依賴例項,但是使用它需要宣告是在哪個 impl 塊中的。

一直使用的 String::from 函式就是一個"關聯函式"。

例項

#[derive(Debug)]
struct Rectangle {
    width: u32,
    height: u32,
}
impl Rectangle {
    fn create(width: u32, height: u32) -> Rectangle {
        Rectangle { width, height }
    }
}
fn main() {
    let rect = Rectangle::create(30, 50);
    println!("{:?}", rect);
}

執行結果:

Rectangle { width: 30, height: 50 }

貼士:結構體 impl 塊可以寫幾次,效果相當於它們內容的拼接!

單元結構體

結構體可以值作為一種象徵而無需任何成員:

struct UnitStruct;

我們稱這種沒有身體的結構體為單元結構體(Unit Struct)。

原文地址:

來自 “ ITPUB部落格 ” ,連結:http://blog.itpub.net/31559985/viewspace-2739853/,如需轉載,請註明出處,否則將追究法律責任。

相關文章