方法語法

struct 可以定義方法,方法與函式類似,使用 fn 關鍵字,也擁有參數與回傳值。

[!IMPORTANT]

與函式不同,方法的第一個參數總是 self,它代表調用該方法的 struct 實例。

定義方法

將之前的 area 函式改寫成 Rectangle struct 上的一個 area 方法。

#[derive(Debug)]
struct Rectangle {
    width: u32,
    height: u32,
}

impl Rectangle { // impl 為 implementation 的縮寫
    fn area(&self) -> u32 { // 注意這裡需要加上 & 來借用,因為我們不需要獲取 Rectangle 實例的所有權
        self.width * self.height
    }
}

fn main() {
    let rect1 = Rectangle { width: 30, height: 50 };

    println!(
        "The area of the rectangle is {} square pixels.",
        rect1.area()
    );
}

Rust 有一個叫自動引用與解引用 (automatic referencing and dereferencing) 的功能。

當使用 object.something() 時,Rust 會根據 something()self 參數設定,自動為 object 加上 &&mut*

#[derive(Debug,Copy,Clone)]
struct Point {
    x: f64,
    y: f64,
}

impl Point {
    // 因為 self 有加上 &,因此當我們呼叫 distance() 時,Rust 會自動為實例加上 &
    fn distance(&self, other: &Point) -> f64 {
        let x_squared = f64::powi(other.x - self.x, 2);
        let y_squared = f64::powi(other.y - self.y, 2);
        f64::sqrt(x_squared + y_squared)
    }
}

fn main() {
    let p1 = Point { x: 0.0, y: 0.0 };
    let p2 = Point { x: 5.0, y: 6.5 };

    // 下面這兩行的意思會是一樣的
    p1.distance(&p2);
    (&p1).distance(&p2);
}

帶有更多參數的方法

我們再加上一個可以用來判斷是否可以包含另外一個長方形的方法,如以下的範例。

fn main() {
    let rect1 = Rectangle { width: 30, height: 50 };
    let rect2 = Rectangle { width: 10, height: 40 };
    let rect3 = Rectangle { width: 60, height: 45 };

    println!("Can rect1 hold rect2? {}", rect1.can_hold(&rect2)); // true
    println!("Can rect1 hold rect3? {}", rect1.can_hold(&rect3)); // false
}

實作 can_hold 方法。

#[derive(Debug)]
struct Rectangle {
    width: u32,
    height: u32,
}

impl Rectangle {
    fn area(&self) -> u32 {
        self.width * self.height
    }

    fn can_hold(&self, other: &Rectangle) -> bool {
        self.width > other.width && self.height > other.height
    }
}

關聯函式

impl 還有另外一個功能,允許在其中定義一個不以 self 當作第一個參數的函式,也被稱為關聯函式。

關聯函式與 struct 相關聯,但並不是方法,因為他們與 struct 的實例無關,前面使用的 String::from 就是一種關聯函式。

[!NOTE]

感覺有點類似於 PHP 的靜態方法。即使沒有實例,也可以直接使用。

#[derive(Debug)]
struct Rectangle {
    width: u32,
    height: u32,
}

impl Rectangle {
    // 定義正方形
    fn square(size: u32) -> Rectangle {
        Rectangle { width: size, height: size }
    }
}

關聯函式使用 :: 調用,例如下方的例子。

let sq = Rectangle::square(10);

多個 impl

struct 允許擁有多個 impl

#[derive(Debug)]
struct Rectangle {
    width: u32,
    height: u32,
}

impl Rectangle {
    fn area(&self) -> u32 {
        self.width * self.height
    }
}

impl Rectangle {
    fn can_hold(&self, other: &Rectangle) -> bool {
        self.width > other.width && self.height > other.height
    }
}

This site uses Just the Docs, a documentation theme for Jekyll.