型強制

特定の状況では、暗黙に型変換を強制することが出来ます。これらの変換は、一般には 単に型を弱くしていて、主にポインタやライフタイム周りに着目されます。 これらはほとんどが、より多くのケースで Rust が "単に動く" ようにするために存在し、 そして大部分において、ほとんど害はありません。

これらは全ての種類の型強制です:

型強制は以下の型の間で認められています:

  • 推移性: T_1 から T_3 但し T_1T_2 に型強制可能で、 T_2T_3 に型強制可能な場合
  • ポインタの弱化:
    • &mut T から &T
    • *mut T から *const T
    • &T から *const T
    • &mut T から *mut T
  • アンサイジング: T から U 但し TCoerceUnsized<U> を実装している場合
  • 参照外しの型強制: 型 &T の式 &x から型 &U の式 &'x 但し TU に参照外しされる場合 (例: 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 が存在し、 TU に型強制される場合、 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);
              ^~~