Open6

Rust基礎

TotsukaTotsuka

バイナリクレート

  • それ単体で実行できる。
  • Cargoではデフォルトで src/main.rsがパッケージ名と同じバイナリクレートとなる。
  • src/bin配下のxxx.rsが個別のバイナリクレートとなる。

バイナリクレートの実行

以下のような構成でバイナリクレートがある場合、

cargo run --bin bin1

を実行することでbin1.rsmain関数が実行できる。

.
├── bin
│   ├── bin1.rs
│   └── bin2.rs
├── main.rs
TotsukaTotsuka

ライブラリクレート

  • パッケージには0個 or 1個のライブラリクレートが持てる
  • src/lib.rsでライブラリクレートを作成
  • 必ずpubにしておく

ライブラリクレートを使う

ライブラリクレートを使うには、どの階層にいても<パッケージ名>::関数名で呼び出すことができる

TotsukaTotsuka

トレイト

  • 任意の方とトレイトを紐づけることを「トレイトを実装する」という
pub mod sample_trait {
    // トレイトを定義
    pub trait Shape {
        fn calc_area(&self) -> f64;
        fn calc_perimeter(&self) -> f64;
        fn do_something(&self) {}
    }

    // 構造体を定義
    pub struct Rectangle {
        width: f64,
        height: f64,
    }

    // 構造体にトレイトを実装
    impl Shape for Rectangle {
        fn calc_area(&self) -> f64 {
            self.width * self.height
        }

        fn calc_perimeter(&self) -> f64 {
            2.0 * (self.width + self.height)
        }

        fn do_something(&self) {
            println!("I am a rectangle");
        }
    }
}

トレイトを引数で受け取る

    pub fn double_area(shape: &impl Shape) -> f64 {
        shape.calc_area() * 2.0
    }

トレイト境界

以下のコードは、Tを型引数としていますが、大小比較できる型か不明なためエラーが発生。
ここでは、大小比較ができるという制約をつける必要がある。この制約のことをジェネリック境界 or トレイト境界と呼ぶ。

fn max<T>(a: T, b: T) -> T {
    if a > b { // ここでエラーが発生
        a
    } else {
        b
    }
}

正しい例①
Tの後に:でTraitを指定。

fn max<T: PartialOrd>(a: T, b: T) -> T {
    if a > b {
        a
    } else {
        b
    }
}

正しい例②
戻り値の後にwhereでトレイト境界を指定。

fn max<T>(a: T, b: T) -> T
    where T: PartialOrd {
    if a > b {
        a
    } else {
        b
    }
}
TotsukaTotsuka

イテレータ

  • 連続したオブジェクトを生成する値
  • オブジェクトを順番に取り扱うための機能を提供する
TotsukaTotsuka

Box

traitを実装した型を表現するには、Box<dyn T>を使用する。

trait Animal {
    fn make_sound(&self);
    fn get_name(&self) -> &str;
}

struct Dog {
    name: String,
}

impl Animal for Dog {
    fn make_sound(&self) {
        print!("わんわん!");
    }

    fn get_name(&self) -> &str {
        &self.name
    }
}

struct Cat {
    name: String,
}

impl Animal for Cat {
    fn make_sound(&self) {
        print!("にゃーにゃー!");
    }

    fn get_name(&self) -> &str {
        &self.name
    }
}

fn main() {
    let animals: Vec<Box<dyn Animal>> = vec![
        Box::new(Dog { name: "ポチ".to_string() }),
        Box::new(Cat { name: "たま".to_string() }),
    ];

    for animal in animals.iter() {
        animal.make_sound();
        println!("名前は{}", animal.get_name());
    }
}

impl, dyn

Box<dyn Animal>

ここを以下のように変更するとエラーが出る。

Box<impl Animal>

implトレイト構文は、関数や固有のメソッドの引数と戻り値の型でのみ許可されています。