Primitive Type never
Expand description
The ! type, also called “never”.
! is the canonical uninhabited type. ! represents the type of diverging computations –
computations which never resolve to any value.
Another way to look at it is that since ! has no values (since it is uninhabited), it is a
marker for unreachable code.
For example, the exit function is defined as returning !, to signify that it doesn’t return
normally (as it exits the process instead). Thus, any code following a call to exit is
unreachable. (panic! works the same way.)
Similarly, return, break, continue, become, and infinite loop expressions
all have type !, as the code following them is unreachable.
fn meow() -> u32 {
let _: ! = return 123;
// code following the `return` is unreachable...
// since it returns from the function
}The let binding above is pointless, but shows that return expressions have type !.
§Never-to-any coercion
The never type can be coerced to any type:
This is sound because a value of type ! can never exist, and any coercion of such a value will
never actually execute.
This is useful when an if branch or match arm returns early (or panics, or falls into an
infinite loop, etc.).
fn mrrrow(option: Option<u32>) {
let value = match option {
// `x` has type `u32`
Some(x) => x,
// `return` has type `!`, which is then coerced to `u32`,
// allowing the `match` to pass type checking.
None => return,
};
// ...
}
fn miau(fallible: impl Fn() -> Result<i64, u32>) -> i64 {
loop {
let err = match fallible() {
Ok(res) => break res,
Err(err) => err,
};
// retry logic...
}
}§Infallible errors & disabling enum variants
The never type can also be used to mark operations as infallible.
Consider the FromStr trait:
When implementing this trait for String, we need to pick a type for
Err. And since converting a string into a string will never result in an
error, we would like to guarantee to the caller that we never return Err(_).
One way to do this is to set the error type to !. Since the never type has no values, the
Err variant of a Result<T, !> cannot be constructed either. Moreover, the compiler can
recognise this fact, and doesn’t require you to handle the Err case:
The same works for any enum, not just Result, and also for any uninhabited type, not just
!:
// An enum with no variants is an example of an uninhabited type
enum Void {}
enum Onomatopoeias {
// This variant can't be created and thus doesn't have to be matched
Miu(!),
// It doesn't matter if there are other fields,
// as long as at least one of them is uninhabited
Nya(u32, !),
// Other uninhabited types have the same effect as the never type
Mjau(Void),
// Variants without uninhabited fields have to be handled as usual of course
Miaow,
// Even though `!` is uninhabited, `Option<!>` is inhabited by the `None` variant
Myaaoo(Option<!>)
}
use Onomatopoeias::*;
_ = |x: Onomatopoeias| match x {
Miaow => 0,
Myaaoo(None) => 1,
};§Implementing traits for !
At first glance there is no reason to implement any traits for !. Many trait methods take
self as an argument, so calling them on ! is impossible.
However, when ! is used as a generic argument, it must still satisfy any trait bounds imposed
on it. For example, Result<T, E> implements Clone if both T and E also implement it.
In order for Result<T, !> to implement Clone, ! must do so as well.
In general, if a trait only has methods taking a self parameter (or &self, or an argument
of type Self, etc.), consider implementing it for !. In such cases the implementation is
trivial, thanks to never-to-any coercion. As an example, take the Debug trait:
impl Debug for ! {
fn fmt(&self, _: &mut fmt::Formatter<'_>) -> fmt::Result {
// we can dereference `self` (which has type `&!`) to get `!`,
// which then coerces to `fmt::Result`
*self
}
}On the other hand, one trait which would not be appropriate to implement for ! is Default:
Since ! has no values, it has no default value either. There is no meaningful implementation
for default, since it would have to return ! – in other words it would need to diverge.
While one could write an implementation using panic! or an infinite loop, or something
alike, that would not be useful.
§! as impl Trait
When prototyping functions, one can use todo! (which has type !) to make the incomplete
code type-check:
However, even though ! can coerce to any type, this does not always work with functions
returning impl Trait:
error[E0277]: `!` is not an iterator
--> src/lib.rs:1:14
|
1 | fn mjav() -> impl Iterator<Item = f32> {
| ^^^^^^^^^^^^^^^^^^^^^^^^^ `!` is not an iterator
2 | todo!()
| ------- return type was inferred to be `!` here
|
= help: the trait `Iterator` is not implemented for `!`This is because impl Trait is not a concrete type, but rather a way to tell the compiler that
a function’s return type is hidden, and the only thing which can be assumed about the hidden
type is that it implements Trait.
In this case, the hidden return type is inferred to be !, which does not implement
Iterator. One fix for this is to explicitly cast ! to a type which implements the trait:
Trait Implementations§
impl Copy for !
impl Eq for !
1.100.0 · Source§impl Error for !
impl Error for !
1.30.0 · Source§fn source(&self) -> Option<&(dyn Error + 'static)>
fn source(&self) -> Option<&(dyn Error + 'static)>
1.0.0 · Source§fn description(&self) -> &str
fn description(&self) -> &str
use the Display impl or to_string()