English | 简体中文 | 繁體中文 | Русский язык | Français | Español | Português | Deutsch | 日本語 | 한국어 | Italiano | بالعربية

Rust 構造体

Rustの構造体(Struct)とタプル(Tuple)は、異なる種類のデータをまとめて一つの全体として扱うことができますが、構造体の各メンバーとその自身には名前があります。そのため、メンバーにアクセスする際にはインデックスを覚える必要がありません。タプルは定義されていない多値の伝達に常用されますが、構造体は一般的なデータ構造の規格化に用いられます。構造体の各メンバーは「フィールド」と呼ばれます。

構造体の定義

これは構造体の定義です:

struct Site {
    domain: String,
    name: String,
    nation: String,
    found: u32
}

注意:Cをよく使う場合/C++Rustでは、struct文は定義にのみ用いられ、例を宣言することはできず、終わりには;シンボルが必要ありません。また、各フィールドの定義の後には、,シンボルで区切ります。

構造体の例

Rustは多くの部分がJavaScriptに影響を受けており、構造体の例示化にはJSONオブジェクトのkey: value文法を使用して定義されています:

let w3codebox = Site {
    domain: String::from("ja.oldtoolbag.com")
    name: String::from("w3codebox")
    nation: String::from("China"),
    found: 2013
};

JSONオブジェクトについてよく分からない場合は、構造を気にせず、フォーマットを覚えておくだけで大丈夫です:

構造体クラス名 {
    フィールド名 : フィールド値,
    ...
}

この利点は、プログラムをより直感的にし、メンバーの値を定義の順序に従わずに入力する必要がなくなります。

構造体の例を示す際に、フィールド名と既存の変数名が同じの場合、書き方が簡略化できます:

let domain = String::from("ja.oldtoolbag.com");
let name = String::from("w3codebox");
let w3codebox = Site {
    domain,  // 同等に domain : domain,
    name,    // 同等に name : name,
    nation: String::from("China"),
    traffic: 2013
};

以下のような状況があります:新しい構造体の例を作成したい場合、多くの属性が既存の構造体の属性と同じに設定される必要があり、ただ一两个字段の値を変更するだけで良い場合、構造体更新構文を使用できます:

let site = Site {
    domain: String::from("ja.oldtoolbag.com")
    name: String::from("w3codebox")
    ..w3codebox
};

注意:..w3codeboxの後にはカンマを置かないことができます。この構文は、他の構造体の例を一成不变的にコピーすることを許可せず、少なくとも一つのフィールドの値を再設定する必要があります:

元組構造体

構造体を定義および使用するよりシンプルな方法があります:元組構造体

元組構造体は形式がタプルの構造体です。

違いは名前と固定の形式を持っていることです。その存在意義は、型を定義する必要があるが複雑すぎない単純なデータを処理するためにあります:

struct Color(u8、u8、u8);
struct Point(f64、f64);
let black = Color(0, 0, 0);
let origin = Point(0.0, 0.0);

「色」および「点座標」は一般的なデータタイプの2種類ですが、もし例を示す際に括弧と2つの名前を書くことで可読性を犠牲にして便利性を失うなら、Rustはこの問題を引き継ぎません。タプル構造体オブジェクトの使用方法はタプルと同じで、.とインデックスを通じてアクセスします:

fn main() {
    struct Color(u8、u8、u8);
    struct Point(f64、f64);
    let black = Color(0, 0, 0);
    let origin = Point(0.0, 0.0);
    println!("black = ({}, {}, {})", black.0, black.1, black.2);
    println!("origin = ({}, {})", origin.0, origin.1);
}

実行結果:

black = (0, 0, 0)
origin = (0, 0)

構造体の所有権

構造体はフィールドの所有権を掌握する必要があります。なぜなら構造体が無効化するとすべてのフィールドが解放されるからです。

これが why この章の例では String タイプを使用し、&str を使用しない理由です。

これは構造体に参照型のフィールドを定義しないことを意味しません。これは「ライフサイクル」メカニズムを通じて実現する必要があります。

しかし「ライフサイクル」の概念がまだ説明しにくいため、後の章で説明します。

構造体の出力

デバッグ中に構造体の例を完全に表示することは非常に役立ちます。しかし、手動で書くと非常に不便です。そこで Rust は整个構造体を出力する便利な方法を提供しています:

#[derive(Debug)]
struct Rectangle {
    width: u32,
    height: u32,
}
fn main() {
    let rect1 = Rectangle { width: 30, height: 50 };
    println!("rect1 is {:?}", rect1);
}

最初の行のように:デバッグライブラリをインポートする必要があります #[derive(Debug)] 、その後 println と print マクロで {:?} 占位符を使用して整个構造体を出力できます:

rect1 is Rectangle { width: 30, height: 50 }

属性が多い場合、別の占位符 {:#?} を使用できます。

出力結果:

rect1 is Rectangle {
    width: 30,
    height: 50
}

構造体メソッド

メソッド(Method)と関数(Function)は似ていますが、構造体の例を操作するために使われます。

もし面向对象的言語を学んだことがあるなら、関数は一般的にクラス定義内に配置され、関数内で this で操作される例が分かっているでしょう。

Rust 言語はオブジェクト指向言語ではありません。これは所有権メカニズムの革新的な点からも分かります。しかし、オブジェクト指向の貴重な思想は Rust で実現できます。

構造体メソッドの最初の引数は &self で、型を宣言する必要はありません。なぜなら self はスタイルではなくキーワードだからです。

矩形の面積を計算する:

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!("rect1's area is {}", rect1.area());
}

出力結果:

rect1's area is 1500

注意,構造体メソッドを呼び出す際に self を記載する必要はありません。これは使いやすさを考慮しています。

一個多參數的インスタンス:

struct Rectangle {
    width: u32,
    height: u32,
}
impl Rectangle {
    fn area(&self) -> u32 {
        self.width * self.height
    }
    fn wider(&self, rect: &Rectangle) -> bool {}}
        self.width > rect.width
    }
}
fn main() {
    let rect1 = Rectangle { width: 30, height: 50 };
    let rect2 = Rectangle { width: 40, height: 20 };
    println!("{}", rect1.wider(&rect2));
}

実行結果:

false

このプログラムは rect1 rect2 もっと広い。

構造体関連関数

「構造体メソッド」を「構造体関数」と呼ばない理由は、この関数が impl ブロックに &self パラメータを持っていないためです。

この関数はオブジェクトに依存しませんが、使用するにはその impl ブロックがどこにあるかを宣言する必要があります。

常に使用している String::from 関数は「関連関数」と呼ばれます。

#[derive(Debug)]
struct Rectangle {
    width: u32,
    height: u32,
}
impl Rectangle {
    fn create(width: u32, height: u32) -> Rectangle {
        Rectangle { width, height }
    }
}
fn main() {
    let rect = Rectangle::create(30, 50);
    println!("{:?}", rect);
}

実行結果:

Rectangle { width: 30, height: 50 }

ヒント:構造体 impl ブロックは何度でも書け、効果はその内容の結合に相当します!

ユニット構造体

構造体はメンバーがなくても象徴的なものとしてのみ使用できます:

struct UnitStruct;

この身体のない構造体をユニット構造体(Unit Struct)と呼びます。