🦀

The Rust Programing Language 3日目

2023/11/02に公開

前回のあらすじ
所有権は案外そこまで難解ではなかった。これはもうほぼrustaceanと言っても過言ではないのでは?
今回は5章

今日の学び

構造体

struct User {
    username: String,
    email: String,
    sign_in_count: u64,
    active: bool,
}
  • structというキーワードで構造体を定義する
    • データクラスみたいなこと?
    • 値オブジェクト作る専用の型みたいな感じだろうか
    • TypeScriptの型定義はこんな感じだったような
let user1 = User {
    email: String::from("someone@example.com"),
    username: String::from("someusername123"),
    active: true,
    sign_in_count: 1,
};
  • 使用時には値を指定してインスタンスを生成する
  • user1.emailのように値を取り出したり、可変ならセットしたりもできる
  • 構造体は全体で可変か不変であり、個別のフィールドで異なる設定にはできない
fn build_user(email: String, username: String) -> User {
    User {
        email,
        username,
        active: true,
        sign_in_count: 1,
    }
}
  • 構造体のフィールド名と変数を同名にすると、初期化の記述を省略できる
    • email: emailと書く必要がない
    • これいいな、嬉しい
let user2 = User {
    email: String::from("another@example.com"),
    username: String::from("anotherusername567"),
    ..user1
};
  • 一部のフィールドのみ変更した構造体を生成するときは、更新記法が使える
    • これもちょいちょい嬉しいことありそう
    • user1の所有権はムーブしないのかなとちょっと思ったけど、しないんだろうな

タプル構造体

  • フィールド名を持たず、型の情報だけを持つタプルのような構造体
  • struct Color(i32, i32, i32);
    • 文章を読んだタイミングでは何に使うんだこれと思ったが、納得
    • 同じようにi32を3つ持つタプル構造体があったとしても、別の型になる
    • タプルと同じように操作できる

ユニット様構造体

  • 一切フィールドを持たない構造体を定義できる(!?)
    • ユニット型て何ですか
    • ある型にトレイトを実装するが、型に保持させるデータが一切ない場面で有効
      • つまり...どういうことだってばよ...!?
      • ちょっとこれは特殊な構造な気がするので一旦理解を諦める

構造体データの所有権

  • 構造体に参照を持たせるのには、ライフタイムという機能を使用する必要がある
    • ライフタイム、お噂はかねがね伺っております
    • これは10章で出てくるとのこと
      • 首洗っときます

printによるデバッグ

struct Rectangle {
    width: u32,
    height: u32,
}

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

    // rect1は{}です
    println!("rect1 is {}", rect1);
}
  • これはできない
    • 構造体にはDisplayが提供されていない
      • {:?}と書くと、Debug`と呼ばれる出力整形を使う
      • #[derive(Debug)]という注釈を追加する必要がある
        • これがトレイトを導出する注釈
          • トレイトを導出するってどういう意味なのかよくわかっていない
        • {:#?}とすると改行して出力される
        • derive注釈はたくさんあるらしい
#[derive(Debug)]
struct Rectangle {
    width: u32,
    height: u32,
}

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

    println!("rect1 is {:?}", rect1);
}

これならできる

メソッド記法

  • メソッドは関数に似ているが、構造体(とその他諸々)の文脈で定義される
    • 第一引数は必ずselfになる
      • メソッドが呼び出されている構造体インスタンスを指す
    • メソッドと関数の違い、ちゃんと理解していなかった気がする
  • Rectangleの文脈内で関数を定義するにはimplブロックを開始する
#[derive(Debug)]
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!(
        "The area of the rectangle is {} square pixels.",
        rect1.area()
    );
}

関連関数

  • implブロック内に、selfを引数にとらない関数を定義できる
    • String::fromも関連関数
    • 構造体の新規インスタンスを返すコンストラクタによく使用される

まとめ

後半眠くて文章が雑になり、ただのコードコピペも増えてしまった、反省
でも構造体については大方理解できたと思うのでヨシ!
DDDとかはJavaなどよりやりやすいのかも?と思った、やってみたい
Javaでもちゃんとやったことないけど

明日は6章、Enum

Discussion