iT邦幫忙

2022 iThome 鐵人賽

DAY 8
0

環境

OS: Windows 10
Editor: Visual Studio Code
Rust version: 1.63.0

定義與實例化

程式寫到一定時候,會想要開始組織它,以便之後再利用以及增加可讀性,這時候就會分散的資料包裝起來。結構,可以說是幾乎每個現代程式語言都會有的功能。

以下我們以三維向量的運算作為範例

如許多語言,定義一個結構(structure),會是以struct或是class開頭:

struct Vector3 {
    x: f64,
    y: f64,
    z: f64,
}

實例化(Instantiate)的話:

let v = Vector3 {
    x: 3.0,
    y: 4.0,
    z: 5.0,
};

又或著是可以用函式實例化:

fn create_vector3(x: f64, y: f64, z: f64) -> Vector3 {
    Vector3 { x, y, z }
}

可以看到上面的用函式的方式,我們把解構的欄位省略了,這在Rsut也是合法的。

利用元組(Tuple)

或是在Rust裡面,我們可以用元組來定義結構,我們把向量的結構改寫:

struct Vector3(f64, f64, f64);

實例化會變成這樣:

let v = Vector3(3.0, 4.0, 5.0);

PS: 我一直覺得tuple是個很神奇的東西,不知道還可以這樣用。

方法(Methods)

方法其實就是針對結構定義的函式,只是換了個名字。

如果要定義方法的話:

impl Vector3 {
    fn length(&self) -> f64 {
        (self.x * self.x + self.y * self.y + self.z * self.z).sqrt()
    }
}

我們把要定義的方法用impl包起來,這表示區塊內都是某個結構的方法實作了,上面我們實作的就是Vector3這個結構。

然後看到方法-length裡面代的參數是&self,這是self: &Self的簡寫,Self這個型別即是我們要實做那個結構型別的別名。

如果不是利用方法的方式,函式的寫法則是會長這樣:

fn length(v: &Vector3) -> f64 {
    (v.x * v.x + v.y * v.y + v.z * v.z).sqrt()
}

最後,我們試試呼叫這個方法:

fn main() {
    let v = Vector3 {
        x: 3.0,
        y: 4.0,
        z: 5.0,
    };

    println!("The length of vector is {}", v.length());
}

可以注意到,我們對傳入的self&借用的方式,確實在這個例子中我們並不想感變原始資料,但跟函式定義的方式一樣,我們使用可變引用

impl Vector3 {
    fn set_x(&mut self, x: f64) {
        self.x = x;
    }
}

測試一下結果...

impl Vector3 {
    fn length(&self) -> f64 {
        (self.x * self.x + self.y * self.y + self.z * self.z).sqrt()
    }

    fn set_x(&mut self, x: f64) {
        self.x = x;
    }
}

fn main() {
    let mut v = Vector3 {
        x: 1.0,
        y: 4.0,
        z: 5.0,
    };

    println!("The length of vector is {}", v.length());

    v.set_x(3.0);

    println!("The length of vector is {}", v.length());
}

關聯函式

定義在impl區塊內的函式,如果不使用定義型別的話,則稱為關聯函式,在前面已經有看一個關聯函示了:

String::from("hello");

from就是String的關聯函式。

上面說到的,不使用定義型別的話,在寫法上指的是這樣:

impl Vector3 {
    fn create(x: f64, y: f64, z: f64) -> Vector3 {
        Vector3 { x, y, z }
    }
}

這樣我們就定義了一個像是建構子(constructor)的關聯函式。

當然,也可以這樣寫,改寫一下length

impl Vector3 {
    fn dot_product(v0: &Vector3, v1: &Vector3) -> f64 {
        v0.x * v1.x + v0.y * v1.y + v0.z * v1.z
    }

    fn length(&self) -> f64 {
        Vector3::dot_product(self, self).sqrt()
    }

Reference


上一篇
[Rust] 字串與string literal
下一篇
[Rust] 枚舉(Enumeration)
系列文
嘗試30天學「不」會Rust18
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言