Rust 隐式类型转换(Coercions)

原创
2020/02/04 10:23
阅读数 2.4K

Rust 隐式类型转换(Coercions)

类型会被隐式转换以适用特定上下文。这种转换主要集中在生存期和指针,通常是弱化类型。这种转换是目的主要是为提供编码便捷性,多数是无害的。

隐式转换规则

  • 传递性原则: 如果 T1 可以隐式转换为 T2,并且 T2 可以隐式转换为 T3,那么 T1 可以隐式转换为 T3

  • 弱化指针:

    • &mut T => &T
    • *mut T => *const T
    • &T => *const T
    • &mut T => *mut T
  • 大小无关化:如果 T 实现了 CoerceUnsized<U>,那么 T 可以隐式转换为 U

  • 解引用:如果 T 解引用到 U(实现 T: Deref<Target = U>),那么可以通过表达式 &*x 将类型为 &T的引用&x 转换为类型为 &U 类型。

  • 所有指针类型(包括智能指针如 BoxRc)都实现了:CoerceUnsized<Pointer<U>> for Pointer<T> where T: Unsize<U>,就是如果 U 去掉大小这个属性后是类型 T,那么 T 的所有指针类型都可以隐式转换为 U 的相同指针类型。无大小系统自动实现。包含以下几种情况:

    • [K; n] => [K]
    • K => dyn Trait 如果 K: Trait
    • 如果 T: Usize<U>,并且类型T在结构体中兄出现一次并且在最后一个域,那么 Foo<..., T, ...> => Foo<..., U, ...>。如果T是被包裹的类型 Bar<T>,那么要求 Bar<T>: Unsize<Bar<U>>

转换发生的地方(转换点)

隐式转换发生在明确表示了所需类型的地方,需要类型推断的地方不会有隐式转换发生。具体而言,将发生在以下地方:

假设有表达式 e 和所需类型 U

  • let、const、static 语句赋值,如 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 }

值得注意的点

如果所需类型是 Trait 时,类型转换的传递性原则无效。也就是说,如果一个转换点需要的类型是 TraitA,如果 U: TraitA,并且类型 T => U 成立,也不能用 T 做转换点的表达式。比如以下代码会报错:

trait Trait {}

fn foo<X: Trait>(t: X) {}

impl<'a> Trait for &'a i32 {}

fn main() {
    let t: &mut i32 = &mut 0;
    foo(t);
}

报错信息:

error[E0277]: the trait bound `&mut i32: Trait` is not satisfied
 --> src/main.rs:9:5
  |
9 |     foo(t);
  |     ^^^ the trait `Trait` is not implemented for `&mut i32`
  |
  = help: the following implementations were found:
            <&'a i32 as Trait>
note: required by `foo`
 --> src/main.rs:3:1
  |
3 | fn foo<X: Trait>(t: X) {}
  | ^^^^^^^^^^^^^^^^^^^^^^

error: aborting due to previous error

即便 &mut i32(类型T)可以转换为实现特性 Trait 的 &i32(类型U),也不可以直接将 &mut i32 作为函数 foo 的参数。

原文连接

展开阅读全文
加载中
点击引领话题📣 发布并加入讨论🔥
打赏
0 评论
0 收藏
0
分享
返回顶部
顶部