サーチ…
構文
- 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
では、 bool
、 isize
、 String
型のmy_bool
、 my_num
、 my_bool
3つのフィールドを持つstruct
を宣言しています。
Rustでstruct
を作成する別の方法は、 タプル構造体を作成することです 。
struct Bar (bool, isize, String);
これは、 bool
、 isize
、 String
順で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);
また、 self
にmut
接頭辞が付いているので、 self
をmut
に戻してから再度返すことができます。 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}
}
}
Gen
のT
に型境界がある場合、それらも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