サーチ…


構文

  • struct Foo {field1:Type1、field2:Type2}
  • let foo = Foo {field1:Type1 :: new()、field2:Type2 :: new()};
  • 構造体バー(Type1、Type2); //タプル型
  • let = = Bar(Type1 :: new()、Type2 :: new());
  • 構造Baz; //単位のような型
  • _ = Bazとする。
  • let Foo {field1、..} = foo; //パターンマッチングでfield1を抽出する
  • let Foo {field1:x、..} = foo; // field1をxとして抽出する
  • foo2 = Foo {field1:Type1 :: new()、.. foo}とする。 //既存のものから構築する
  • impl Foo {fn fiddle(&self){}} // Fooのインスタンスメソッドを宣言します
  • impl Foo {fn tweak(&mut self){}} // Fooの可変インスタンスメソッドを宣言します
  • impl Foo {fn double(self){}} // Fooのインスタンスメソッドを宣言します
  • impl Foo {fn new(){}} // Fooの関連メソッドを宣言します

構造の定義

Rustのstructは、 structキーワードを使用して定義されます。構造の最も一般的な形式は、一連の名前付きフィールドで構成されています。

struct Foo {
    my_bool: bool,
    my_num: isize,
    my_string: String,
}

上のmy_stringでは、 boolisizeString型のmy_boolmy_nummy_bool 3つのフィールドを持つstructを宣言しています。

Rustでstructを作成する別の方法は、 タプル構造体を作成することです

struct Bar (bool, isize, String);

これは、 boolisizeString順で3つの名前のないフィールドを持つ新しい型のBar定義します。特定の型に対して新しい "名前"を効果的に導入するため、これはnewtypeパターンと呼ばれます。ただし、 typeキーワードを使用して作成されたエイリアスよりも強力です。 Barは完全に機能する型です。つまり、独自のメソッドを記述することができます(下記参照)。

最後に、 ユニットのような構造体と呼ばれるフィールドのない structを宣言します:

struct Baz;

これは、模倣やテスト(traitを簡単に実装したい場合)やマーカータイプとして便利です。しかし、一般的に、あなたは多くのユニットのような構造体に出くわすことはまずありません。

Rustのstructフィールドは、デフォルトですべてprivateであることに注意してください。つまり、型を定義するモジュールの外部のコードからはアクセスできません。フィールドのpubキーワードを付けると、そのフィールドを一般公開することができます。さらに、 struct自体はprivateです。他のモジュールがその型を利用できるようにするには、 struct定義の前にpub付ける必要があります。

pub struct X {
    my_field: bool,
    pub our_field: bool,
}

構造体値の作成と使用

以下のstruct定義を考えてみましょう:

struct Foo {
    my_bool: bool,
    my_num: isize,
    my_string: String,
}
struct Bar (bool, isize, String);
struct Baz;

これらの型の新しい構造体値を作成するのは簡単です:

let foo = Foo { my_bool: true, my_num: 42, my_string: String::from("hello") };
let bar = Bar(true, 42, String::from("hello"));
let baz = Baz;

を使用して構造体のフィールドにアクセスします.

assert_eq!(foo.my_bool, true);
assert_eq!(bar.0, true); // tuple structs act like tuples

構造体への可変バインディングは、そのフィールドを変更することができます:

let mut foo = foo;
foo.my_bool = false;
let mut bar = bar;
bar.0 = false;

Rustのパターンマッチング機能を使用してstruct内部を覗くこともできます:

// creates bindings mb, mn, ms with values of corresponding fields in foo
let Foo { my_bool: mb, my_num: mn, my_string: ms } = foo;
assert_eq!(mn, 42);
// .. allows you to skip fields you do not care about
let Foo { my_num: mn, .. } = foo;
assert_eq!(mn, 42);
// leave out `: variable` to bind a variable by its field name
let Foo { my_num, .. } = foo;
assert_eq!(my_num, 42);

または、Rustの更新構文を使用して2番目の構造体を「テンプレート」として使用して構造体を作成します

let foo2 = Foo { my_string: String::from("world"), .. foo };
assert_eq!(foo2.my_num, 42);

構造メソッド

構造体(すなわち、「オン」と呼ぶことができる機能のメソッド宣言するstruct 、またはその値structタイプ)を作成implブロック:

impl Foo {
    fn fiddle(&self) {
        // "self" refers to the value this method is being called on
        println!("fiddling {}", self.my_string);
    }
}

// ...
foo.fiddle(); // prints "fiddling hello"

&selfは、 fiddleメソッドを呼び出すためにstruct Fooインスタンスへの不変参照が必要であることを示します。インスタンスの変更(フィールドの変更など)を行う場合は、代わりに&mut self (可変参照)を使用します。

impl Foo {
    fn tweak(&mut self, n: isize) {
        self.my_num = n;
    }
}

// ...
foo.tweak(43);
assert_eq!(foo.my_num, 43);

最後に、我々はまた、使用することができself (の欠如に注意&受信機として)。これには、呼び出し側がインスタンスを所有している必要があり、メソッドを呼び出すときにインスタンスを移動させます。これは、既存のインスタンスを消費、破棄、または完全に変換する場合に便利です。そのようなユースケースの1つの例は、「連鎖」メソッドを提供することです。

impl Foo {
    fn double(mut self) -> Self {
        self.my_num *= 2;
        self
    }
}

// ...
foo.my_num = 1;
assert_eq!(foo.double().double().my_num, 4);

また、 selfmut接頭辞が付いているので、 selfmutに戻してから再度返すことができます。 doubleメソッドの戻り値の型もまた説明を必要とします。 implブロック内のSelfは、 impl適用される型(この場合はFoo )を参照します。ここでは、型のシグネチャの再入力を避けるのが便利な省略形ですが、特性では、特定の特性を実装する基になる型を参照するために使用できます。

struct 関連メソッド (一般に他の言語では「クラスメソッド」と呼ばれる)を宣言するには、単にself引数を省略します。そのようなメソッドは、 struct型ではなく、その型で呼び出されます。

impl Foo {
    fn new(b: bool, n: isize, s: String) -> Foo {
        Foo { my_bool: b, my_num: n, my_string: s }
    }
}

// ...
// :: is used to access associated members of the type
let x = Foo::new(false, 0, String::from("nil"));
assert_eq!(x.my_num, 0);

構造体メソッドは、現在のモジュールで宣言された型に対してのみ定義できます。さらに、フィールドと同様に、すべての構造体メソッドはデフォルトでプライベートであるため、同じモジュール内のコードでのみ呼び出すことができます。他の場所から呼び出し可能にするには、 pubキーワードを定義の前に付けることができます。

一般的な構造

構造体は、1つ以上の型パラメータに対して汎用にすることができます。これらの型は、型を参照するときに<>囲みます。

struct Gen<T> {
    x: T,
    z: isize,
}

// ...
let _: Gen<bool> = Gen{x: true, z: 1};
let _: Gen<isize> = Gen{x: 42, z: 2};
let _: Gen<String> = Gen{x: String::from("hello"), z: 3};

コンマを使用して複数のタイプを指定できます。

struct Gen2<T, U> {
    x: T,
    y: U,
}

// ...
let _: Gen2<bool, isize> = Gen2{x: true, y: 42};

型パラメータは型の一部であるため、同じ基底型で異なるパラメータを持つ2つの変数は互換性がありません。

let mut a: Gen<bool> = Gen{x: true, z: 1};
let b: Gen<isize> = Gen{x: 42, z: 2};
a = b; // this will not work, types are not the same
a.x = 42; // this will not work, the type of .x in a is bool

型パラメータの割り当てに関係なくstructを受け入れる関数を記述したい場合、その関数も汎用化する必要があります:

fn hello<T>(g: Gen<T>) {
    println!("{}", g.z); // valid, since g.z is always an isize
}

しかし、いつもgx印刷できる関数を書こうと思ったらどうでしょうか? Tを表示可能なタイプに制限する必要があります。タイプ境界でこれを行うことができます:

use std::fmt;
fn hello<T: fmt::Display>(g: Gen<T>) {
    println!("{} {}", g.x, g.z);
}

hello関数は、 T型がfmt::Display実装するGenインスタンスに対してのみ定義されるようになりました。たとえば、 Gen<(bool, isize)>Gen<(bool, isize)>と、コンパイラはその型に対してhelloが定義されていないと不満をGen<(bool, isize)>ます。

また、 struct型パラメーターに直接型境界を使用して、そのstructを特定の型に対してのみ構築できることを示すこともできます。

use std::hash::Hash;
struct GenB<T: Hash> {
    x: T,
}

GenBアクセスできるすべての関数は、 xの型がHash実装していることを知り、したがって.x.hash()呼び出すことができます。同じパラメータの複数の型境界は、 +区切って指定できます。

関数と同じように、 whereキーワードを使って<>後ろに型の境界を置くことができます:

struct GenB<T> where T: Hash {
    x: T,
}

これは同じセマンティックな意味を持ちますが、複雑な境界がある場合には、シグネチャを読みやすくフォーマットすることができます。

型パラメータは、インスタンスメソッドやstruct関連メソッドでも使用できます。

// note the <T> parameter for the impl as well
// this is necessary to say that all the following methods only
// exist within the context of those type parameter assignments
impl<T> Gen<T> {
    fn inner(self) -> T {
        self.x
    }
    fn new(x: T) -> Gen<T> {
        Gen{x: x}
    }
}

GenTに型境界がある場合、それらもimpl型境界に反映される必要があります。また、型が特定のプロパティを満たしている場合にのみ、指定されたメソッドが存在すると言うように厳密にimpl境界を作ることもできます。

impl<T: Hash + fmt::Display> Gen<T> {
    fn show(&self) {
        println!("{}", self.x);
    }
}

// ...
Gen{x: 42}.show(); // works fine
let a = Gen{x: (42, true)}; // ok, because (isize, bool): Hash
a.show(); // error: (isize, bool) does not implement fmt::Display


Modified text is an extract of the original Stack Overflow Documentation
ライセンスを受けた CC BY-SA 3.0
所属していない Stack Overflow