Progrust Library.

// dictionary

タプル構造体.

タプル構造体(tuple struct)は、フィールドに名前を付けずに定義する構造体です。各フィールドは.0.1のように位置で参照し、タプル型と同じ感覚で扱えます。フィールド名を付けるほどでもないけれど、値のまとまりに型としての名前は与えたい、という場面で使います。

定義すると型名と同じ名前のコンストラクタが同時に作られるため、インスタンスはPoint(3, 5)のように関数呼び出しの形で生成します1

struct Point(i32, i32);

fn main() {
    let shop = Point(3, 5); // お店の位置(x, y)
    println!("x座標: {}, y座標: {}", shop.0, shop.1);
}
Playgroundで開く

タプル/構造体との違い

タプル・タプル構造体・構造体の違いは次のとおりです。

フィールド名 型としての名前 分解の書き方
タプル なし(位置) なし let (x, y) = p;
タプル構造体 なし(位置) あり let Point(x, y) = p;
構造体 あり あり let Point { x, y } = p;

タプルと違い、分解の際は型名を書く必要があります。

ニュータイプパターン

フィールドが1つだけのタプル構造体で既存の型を包み、意味の違いを型として表す書き方はニュータイプパターンと呼ばれます。素のu32整数型)のままでは取り違えてもコンパイラが気づけない値も、包んでしまえば別の型として区別されます。

struct PriceExcludingTax(u32); // 税抜き価格
struct PriceIncludingTax(u32); // 税込み価格

fn print_total(price: PriceIncludingTax) {
    println!("お会計は{}円です", price.0);
}

fn main() {
    let price = PriceExcludingTax(1000);
    print_total(price); // エラー: E0308(税抜きを税込みとして渡している)
}
Playgroundで開く

補足

コンストラクタは関数として持ち回せる

コンストラクタは実体が関数のため、mapのような高階関数へそのまま渡せます。

struct Yen(u32);

fn main() {
    let prices = vec![120, 250, 380];
    let yens: Vec<Yen> = prices.into_iter().map(Yen).collect(); // Yenを関数として渡す
    println!("2つ目: {}円", yens[1].0);
}
Playgroundで開く
メソッドの定義やDebug出力も同じ

タプル構造体にもimplブロックメソッドを定義でき、#[derive(Debug)]も同じように使えます。{:?}での出力はPoint(3, 5)の形になります(コンソール出力も参照)。

#[derive(Debug)]
struct Point(i32, i32);

impl Point {
    fn distance_from_origin(&self) -> f64 {
        ((self.0 * self.0 + self.1 * self.1) as f64).sqrt()
    }
}

fn main() {
    let shop = Point(3, 4);
    println!("{shop:?}");                      // Point(3, 4)
    println!("{}", shop.distance_from_origin()); // 5
}
Playgroundで開く
フィールドを持たない構造体

フィールドリストごと省略したstruct Marker;は、タプル構造体ではなくユニット様構造体と呼ばれる別の形になります。

Footnotes

  1. The Rust Reference: Structs — 型の定義に加えて、値の名前空間に同名のコンストラクタを定義すると述べています。

この辞書が使われているページ

backlinks 5

  1. 辞書ユニット様構造体
  2. 辞書構造体
  3. 辞書列挙型
  4. 動かして学ぶRustプログラミング問題集 › 第11章 列挙型とmatch式
  5. 動かして学ぶRustプログラミング問題集 › 第9章 構造体