Keyboard shortcuts

Press or to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

関連関数とメソッド

一部の関数は、特定の型に結び付いています。これには 2 つの形式があります: 関連関数とメソッドです。関連関数は一般的に型に対して定義される関数であり、メソッドは型の特定のインスタンスに対して呼び出される関連関数です。

struct Point {
    x: f64,
    y: f64,
}

// 実装ブロック。すべての `Point` の関連関数とメソッドはここに入ります
impl Point {
    // この関数は特定の型、つまり Point に関連付けられているため、
    // 「関連関数」です。
    //
    // 関連関数はインスタンスを使って呼び出す必要はありません。
    // これらの関数は一般的にコンストラクターのように使われます。
    fn origin() -> Point {
        Point { x: 0.0, y: 0.0 }
    }

    // 2 つの引数を取る、別の関連関数:
    fn new(x: f64, y: f64) -> Point {
        Point { x: x, y: y }
    }
}

struct Rectangle {
    p1: Point,
    p2: Point,
}

impl Rectangle {
    // これはメソッドです
    // `&self` は `self: &Self` の糖衣構文で、`Self` は
    // 呼び出し元オブジェクトの型です。この場合、`Self` = `Rectangle` です
    fn area(&self) -> f64 {
        // `self` はドット演算子を介して構造体フィールドへのアクセスを提供します
        let Point { x: x1, y: y1 } = self.p1;
        let Point { x: x2, y: y2 } = self.p2;

        // `abs` は、呼び出し元の絶対値を返す `f64` のメソッドです
        ((x1 - x2) * (y1 - y2)).abs()
    }

    fn perimeter(&self) -> f64 {
        let Point { x: x1, y: y1 } = self.p1;
        let Point { x: x2, y: y2 } = self.p2;

        2.0 * ((x1 - x2).abs() + (y1 - y2).abs())
    }

    // このメソッドは、呼び出し元オブジェクトがミュータブルであることを要求します
    // `&mut self` は `self: &mut Self` に脱糖されます
    fn translate(&mut self, x: f64, y: f64) {
        self.p1.x += x;
        self.p2.x += x;

        self.p1.y += y;
        self.p2.y += y;
    }
}

// `Pair` はリソース、つまりヒープに割り当てられた 2 つの整数を所有します
struct Pair(Box<i32>, Box<i32>);

impl Pair {
    // このメソッドは、呼び出し元オブジェクトのリソースを「消費」します
    // `self` は `self: Self` に脱糖されます
    fn destroy(self) {
        // `self` を分配束縛します
        let Pair(first, second) = self;

        println!("Pair({}, {}) を破棄しています", first, second);

        // `first` と `second` はスコープを抜け、解放されます
    }
}

fn main() {
    let rectangle = Rectangle {
        // 関連関数はダブルコロンを使って呼び出されます
        p1: Point::origin(),
        p2: Point::new(3.0, 4.0),
    };

    // メソッドはドット演算子を使って呼び出されます
    // 最初の引数 `&self` は暗黙的に渡されることに注意してください。すなわち、
    // `rectangle.perimeter()` === `Rectangle::perimeter(&rectangle)` です
    println!("Rectangle の周囲の長さ: {}", rectangle.perimeter());
    println!("Rectangle の面積: {}", rectangle.area());

    let mut square = Rectangle {
        p1: Point::origin(),
        p2: Point::new(1.0, 1.0),
    };

    // エラー!`rectangle` はイミュータブルですが、このメソッドはミュータブルな
    // オブジェクトを要求します
    //rectangle.translate(1.0, 0.0);
    // TODO ^ この行のコメントを解除してみてください

    // OK!ミュータブルなオブジェクトはミュータブルなメソッドを呼び出せます
    square.translate(1.0, 1.0);

    let pair = Pair(Box::new(1), Box::new(2));

    pair.destroy();

    // エラー!前の `destroy` 呼び出しが `pair` を「消費」しました
    //pair.destroy();
    // TODO ^ この行のコメントを解除してみてください
}