Progrust Library.

// dictionary

ユニット様構造体.

ユニット様構造体(unit-like struct)は、フィールドを1つも持たない構造体です。struct Marker;のようにフィールドリストごと省略して定義します。保持する値がない点がユニット型()に似ているため、この名前で呼ばれます。

定義すると型と同じ名前の定数が暗黙に作られるため1Markerと書くだけでインスタンスが得られます。

struct TaxCalculator; // 税率10%固定。覚えておくべきデータがない

impl TaxCalculator {
    fn total(&self, price: u32) -> u32 {
        price * 110 / 100
    }
}

fn main() {
    let calculator = TaxCalculator; // 型名をそのまま書くとインスタンスになる
    println!("税込み: {}円", calculator.total(1000));
}
Playgroundで開く

使いどころ

フィールドがなくてもimplブロックは書けるので、メソッド関連関数を持たせられます。上の例のように状態は持たずに処理だけをまとめたい型や、データは持たせずトレイトの実装だけを与えたいマーカー型が主な用途です。

フィールドを持たない3つの書き方

フィールドが0個の構造体は次の3通りに書けます。型としてはどれもフィールドを持ちませんが、同じ名前で値の名前空間に何が定義されるかが異なります。

定義 種類 Marker単体の意味
struct Marker; ユニット様構造体 インスタンス(暗黙の定数)
struct Marker {} フィールド0個の構造体 値ではない(E0423エラー)
struct Marker(); フィールド0個のタプル構造体 コンストラクタ関数

struct Marker {}のような波括弧での生成はどの形でも書けるため、違いが出るのはMarkerと単体で書いたときです。struct Marker;struct Marker {}const Marker: Marker = Marker {};を同時に書いたのと等価で1、単体でインスタンスになるのはこの形だけです。

補足

サイズは0バイト・Debug出力は型名

ユニット様構造体はフィールドを持たないため、実行時のメモリを占有しません。名前付きフィールドの構造体と同じく#[derive(Debug)]も使え、{:?}では型名がそのまま出力されます(コンソール出力も参照)。

#[derive(Debug)]
struct Marker;

fn main() {
    println!("{}バイト", size_of::<Marker>()); // 0バイト
    println!("{:?}", Marker);                  // Marker
}
Playgroundで開く
標準ライブラリでの例

std::marker::PhantomData標準ライブラリのマーカー型で、ジェネリクスを伴うユニット様構造体としてpub struct PhantomData<T> where T: ?Sized;と宣言されています2。実際に値を持たないまま「この型を使っているつもり」という情報だけをコンパイラに伝える、マーカー型の代表例です。

Footnotes

  1. The Rust Reference: Structs — フィールドリストを完全に省略した構造体をunit-like structと呼び、同名の定数を暗黙に定義すると述べています。 2

  2. std::marker::PhantomData — 宣言そのものが記載されています。

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

backlinks 3

  1. 辞書タプル構造体
  2. 辞書構造体
  3. 動かして学ぶRustプログラミング問題集 › 第9章 構造体