型強制
特定の状況では、暗黙に型変換を強制することが出来ます。これらの変換は、一般には 単に型を弱くしていて、主にポインタやライフタイム周りに着目されます。 これらはほとんどが、より多くのケースで Rust が "単に動く" ようにするために存在し、 そして大部分において、ほとんど害はありません。
これらは全ての種類の型強制です:
型強制は以下の型の間で認められています:
- 推移性:
T_1
からT_3
但しT_1
がT_2
に型強制可能で、T_2
がT_3
に型強制可能な場合 - ポインタの弱化:
&mut T
から&T
*mut T
から*const T
&T
から*const T
&mut T
から*mut T
- アンサイジング:
T
からU
但しT
がCoerceUnsized<U>
を実装している場合 - 参照外しの型強制: 型
&T
の式&x
から型&U
の式&'x
但しT
がU
に参照外しされる場合 (例:T: Deref<Target=U>
)
CoerceUnsized<Pointer<U>> for Pointer<T> where T: Unsize<U>
は
全てのポインタ型 (Box や Rc のようなスマートポインタを含む) で実装されています。
アンサイズは自動的にのみ実装され、以下の変換を有効にします。
[T; n]
=>[T]
T
=>Trait
但しT: Trait
Foo<..., T, ...>
=>Foo<..., U, ...>
但しT: Unsize<U>
Foo
は構造体Foo
の最後のフィールドだけがT
を含む型であるT
は他のフィールドの一部となっていないBar<T>: Unsize<Bar<U>>
但しFoo
の最後のフィールドがBar<T>
の型である場合
型強制は、型強制サイトで起こります。明確に型が指定されている全ての場所で、
その型への型強制が発生します。もし推論が必要ならば、型強制は行われません。
余すことなく言えば、式 e
に対する型 U
への型強制サイトは以下の通りです。
- let 文、 static、 const:
let x: U = e
- 関数に対する引数:
takes_a_U(e)
- 返される全ての式:
fn foo() -> U { e }
- 構造体リテラル:
Foo { some_u: e }
- 配列リテラル:
let x: [U; 10] = [e, ..]
- タプルリテラル:
let x: (U, ..) = (e, ..)
- ブロックの最後の式:
let x: U = { ..; e }
トレイトをマッチさせる場合、型強制が行われないことに注意してください (レシーバは例外です、
以下を見てください) 。もしある型 U
に対する impl が存在し、 T
が U
に型強制される場合、 T
に対しては
実装が構成されません。例えば、以下の例では t
が &T
に型強制されても問題なく、 &T
に対する impl が存在するにも関わらず、
型チェックに通りません。
trait Trait {}
fn foo<X: Trait>(t: X) {}
impl<'a> Trait for &'a i32 {}
fn main() {
let t: &mut i32 = &mut 0;
foo(t);
}
<anon>:10:5: 10:8 error: the trait bound `&mut i32 : Trait` is not satisfied [E0277]
(エラー: トレイト境界 `&mut i32: Trait` が満たされていません)
<anon>:10 foo(t);
^~~