强制转换(Coercions)

在某些情况下,类型可以被隐含地强制改变.这些变化通常只会 削弱(weakening) 类型,主要集中在指针和生命周期.它们主要用于使Rust在更多情况下”正常工作(just work)”,并且在很大程度上是无害的.

这是所有种类的强制转换:

以下类型之间允许强制转换:

  • 传递性(Transitivity):T_1T_3,其中T_1强制转换为T_2,T_2强制转换为T_3

  • 指针弱化(Pointer Weakening):

    • &mut T&T

    • *mut T*const T

    • &T*const T

    • &mut T*mut T

  • 无大小(Unsizing):如果T实现CoerceUnsized<U>,则TU

  • 解引用强制(Deref coercion):如果T解引用为U(即T: Deref<Target=U>),则类型&T的表达式&x到类型&U的表达式&*x

  • *函数指针的非捕获闭包(RFC 1558),例如|| 8usizefn() -> usize

CoerceUnsized<Pointer<U>> for Pointer<T> where T: Unsize<U>是针对所有指针类型实现的(包括智能指针,如Box和Rc).Unsize仅自动实现,并启用以下转换:

  • [T; n] => [T]

  • T => dyn Trait 其中 T: Trait

  • Foo<..., T, ...> => Foo<..., U, ...>其中:

    • T: Unsize<U>

    • Foo是一个结构

    • 只有Foo的最后一个字段有涉及T的类型

    • T不是任何其他字段的类型的一部分

    • Bar<T>: Unsize<Bar<U>>,如果Foo的最后一个字段的类型为Bar<T>

强制转换发生在 强制地点(coercion site) .显式键入的任何位置都会导致对其类型的强制转换.如果需要进行推断,则不会进行强制转换.详尽地说,表达式e到类型U的强制地点是:

  • let语句,静态和常量: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 }

请注意,匹配traits时不执行强制转换(接收者(receivers)除外,见下文).如果有某种类型U的impl并且T强制转为U,那么这不构成T的实现.例如,以下将不会通过类型检查,即使t可以强制转换为&T并且存在&T的impl:

  1. trait Trait {}
  2. fn foo<X: Trait>(t: X) {}
  3. impl<'a> Trait for &'a i32 {}
  4. fn main() {
  5. let t: &mut i32 = &mut 0;
  6. foo(t);
  7. }
  1. error[E0277]: the trait bound `&mut i32: Trait` is not satisfied
  2. --> src/main.rs:9:5
  3. |
  4. 9 | foo(t);
  5. | ^^^ the trait `Trait` is not implemented for `&mut i32`
  6. |
  7. = help: the following implementations were found:
  8. <&'a i32 as Trait>
  9. note: required by `foo`
  10. --> src/main.rs:3:1
  11. |
  12. 3 | fn foo<X: Trait>(t: X) {}
  13. | ^^^^^^^^^^^^^^^^^^^^^^
  14. error: aborting due to previous error