changed 5 years ago
Linked with GitHub

Rust勉強会 第3回

4章 構造体で構造化!

2020/08/21 堀川由人


本日のメニュー

  1. 構造体の定義
  2. プログラム例
  3. メソッド記法

プレゼン20分くらい+議論10分位で18:30前後終了を目指します。


構造体の定義


struct構文

構造体を定義する

struct User {
    username: String,
    email: String,
    sign_in_count: u64,
    active: bool, // ここの,は無くてもok
}

インスタンス作成

インスタンスをつくる(順番は気にしなくてOK)

let user1 = User {
    email: String::from("someone@example.com"),
    username: String::from("someusername123"),
    active: true,
    sign_in_count: 1,
};

フィールドの変更(2/2)

エラーになる例

let user1 = User {
    email: String::from("someone@example.com"),
    username: String::from("someusername123"),
    active: true,
    sign_in_count: 1,
};
user1.active = false

フィールドの変更(2/2)

ここでもフィールドを変更する場合はmutが必要

let mut user1 = User {
    email: String::from("someone@example.com"),
    username: String::from("someusername123"),
    active: true,
    sign_in_count: 1,
};
user1.active = false

インスタンスを作る関数(1/2)

2つのString引数を取ってUserを返す

fn build_user(email: String, username: String) -> User {
    User {
        email: email,
        username: username,
        active: true,
        sign_in_count: 1,
    }
}

インスタンスを作る関数(2/2)

実は省略可能

fn build_user(email: String, username: String) -> User {
    User {
        email,
        username,
        active: true,
        sign_in_count: 1,
    }
}

インスタンスの構成(他からの参照)

他のuser2を定義. ただし足りないものはuser1から

let user1 = User {
    email: String::from("someone@example.com"),
    username: String::from("someusername123"),
    active: true,
    sign_in_count: 1,
};

let user2 = User {
    email: String::from("another@example.com"),
    username: String::from("anotherusername567"),
    ..user1
};

ほぼタプルの構造体

引数の順番のみが重要な場合

struct Color(i32, i32, i32);
struct Point(i32, i32, i32);

let black = Color(0, 0, 0);
let origin = Point(0, 0, 0);

(個人的にはRGBかBGRを明記したいので避けたい)


プログラム例


長方形の面積(愚直に)

fn main() {
    let width1 = 30;
    let height1 = 50;
    println!("The area is {}.", area(width1, height1));
}
fn area(width: u32, height: u32) -> u32 {
    width * height
}

長方形の面積(構造体)

struct Rectangle {
    width: u32,
    height: u32,
}
fn main() {
    let rect1 = Rectangle { width: 30, height: 50 };
    println!("The area is {}.", area(&rect1));
}
fn area(rectangle: &Rectangle) -> u32 {
    rectangle.width * rectangle.height
}

Rectangleのprintln!(1/2)

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

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

これはエラー(標準的なRectangle->Stringが無い)


Rectangleのprintln!(2/2)

#[derive(Debug)]
struct Rectangle {
    width: u32,
    height: u32,
}
fn main() {
    let rect1 = Rectangle { width: 30, height: 50 };
    println!("rect1 is {:?}", rect1);
}
  • #[derive(Debug)]でRectangleにデバッグ宣言
  • {:?}で構造体をよしなに文字列に変換

メソッドなど


Rectangle

#[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 is {}.", rect1.area());
}

impl <struct>内にメソッドを定義
implement: 実装


implの書き方

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

impl Rectangle {
    fn diagonal(&self) -> f64 {
        ((self.width * self.width + self.height * self.height) as f64).sqrt()
    }
}

分かれててもok


複数のRectangle

impl Rectangle {
    fn can_hold(&self, other: &Rectangle) -> bool {
        self.width > other.width && self.height > other.height
    }
}
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
}


関連関数

impl Rectangle {
    fn square(size: u32) -> Rectangle {
        Rectangle { width: size, height: size }
    }
}
let sq = Rectangle::square(3);

として正方形が定義できる.
関連関数はメソッドとは呼ばれない


まとめ・所感


まとめ

  • struct
    • 通常の構造体
    • 名前付きタプル
    • デバッグオプション・省略記法など
  • impl
    • メソッドの定義
    • 関連関数の定義

fieldについて

  • fieldを変更するためにはmutが必要

(Rustでは当たり前なのだとと思いますが)Juliaでは

mutable struct hoge end

struct fuga end

によってfieldの変更可能/不能な構造体を分けていたので少し意外に感じました


モチベーション

  • 欲しい!
    • (個人的には)応用先がまだ見えてないので手が遅い感じがあります。
    • 数値計算を試そうと思ってたのですが、資料に間に合わず…。
  • 原山さんの次々回に期待してます
    Image Not Showing Possible Reasons
    • The image file may be corrupted
    • The server hosting the image is unavailable
    • The image path is incorrect
    • The image format is not supported
    Learn More →

参考資料

https://doc.rust-jp.rs/book/second-edition/ch05-00-structs.html

Select a repo