Coercions
Types can implicitly be coerced to change in certain contexts. These changes aregenerally just weakening of types, largely focused around pointers andlifetimes. They mostly exist to make Rust “just work” in more cases, and arelargely harmless.
Here’s all the kinds of coercion:
Coercion is allowed between the following types:
- Transitivity:
T_1
toT_3
whereT_1
coerces toT_2
andT_2
coerces toT_3
- Pointer Weakening:
&mut T
to&T
*mut T
to*const T
&T
to*const T
&mut T
to*mut T
- Unsizing:
T
toU
ifT
implementsCoerceUnsized<U>
- Deref coercion: Expression
&x
of type&T
to&*x
of type&U
ifT
derefs toU
(i.e.T: Deref<Target=U>
)
CoerceUnsized<Pointer<U>> for Pointer<T> where T: Unsize<U>
is implementedfor all pointer types (including smart pointers like Box and Rc). Unsize isonly implemented automatically, and enables the following transformations:
[T; n]
=>[T]
T
=>dyn Trait
whereT: Trait
Foo<..., T, ...>
=>Foo<..., U, ...>
where:T: Unsize<U>
Foo
is a struct- Only the last field of
Foo
has type involvingT
T
is not part of the type of any other fieldsBar<T>: Unsize<Bar<U>>
, if the last field ofFoo
has typeBar<T>
Coercions occur at a coercion site. Any location that is explicitly typedwill cause a coercion to its type. If inference is necessary, the coercion willnot be performed. Exhaustively, the coercion sites for an expression e
totype U
are:
- let statements, statics, and consts:
let x: U = e
- Arguments to functions:
takes_a_U(e)
- Any expression that will be returned:
fn foo() -> U { e }
- Struct literals:
Foo { some_u: e }
- Array literals:
let x: [U; 10] = [e, ..]
- Tuple literals:
let x: (U, ..) = (e, ..)
- The last expression in a block:
let x: U = { ..; e }
Note that we do not perform coercions when matching traits (except forreceivers, see below). If there is an impl for some type U
and T
coerces toU
, that does not constitute an implementation for T
. For example, thefollowing will not type check, even though it is OK to coerce t
to &T
andthere is an impl for &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