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:
Implementations§
Trait Implementations§
impl Copy for !
1.100.0 (const: unstable) · Source§impl Eq for !
impl Eq for !
1.0.0 (const: unstable) · Source§#[doc(hidden)]fn assert_receiver_is_total_eq(&self)
#[doc(hidden)]fn assert_receiver_is_total_eq(&self)
implementation detail of #[derive(Eq)]
Source§#[doc(hidden)]fn assert_fields_are_eq(&self)
#[doc(hidden)]fn assert_fields_are_eq(&self)
derive_eq_internals)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)>
Source§#[doc(hidden)]fn type_id(&self, _: Internal) -> TypeIdwhere
Self: 'static,
#[doc(hidden)]fn type_id(&self, _: Internal) -> TypeIdwhere
Self: 'static,
error_type_id #60784)TypeId of self.1.0.0 · Source§fn description(&self) -> &str
fn description(&self) -> &str
use the Display impl or to_string()
1.100.0 (const: unstable) · Source§impl From<!> for TryFromIntError
impl From<!> for TryFromIntError
Source§fn from(never: !) -> TryFromIntError
fn from(never: !) -> TryFromIntError
1.36.0 (const: unstable) · Source§impl From<!> for TryFromSliceError
impl From<!> for TryFromSliceError
Source§fn from(x: Infallible) -> TryFromSliceError
fn from(x: Infallible) -> TryFromSliceError
1.100.0 (const: unstable) · Source§impl Ord for !
impl Ord for !
1.21.0 (const: unstable) · Source§fn max(self, other: Self) -> Selfwhere
Self: Sized,
fn max(self, other: Self) -> Selfwhere
Self: Sized,
1.21.0 (const: unstable) · Source§fn min(self, other: Self) -> Selfwhere
Self: Sized,
fn min(self, other: Self) -> Selfwhere
Self: Sized,
1.100.0 (const: unstable) · Source§impl PartialOrd for !
impl PartialOrd for !
Source§#[doc(hidden)]fn __chaining_lt(&self, other: &Rhs) -> ControlFlow<bool>
#[doc(hidden)]fn __chaining_lt(&self, other: &Rhs) -> ControlFlow<bool>
partial_ord_chaining_methods)self == other, returns ControlFlow::Continue(()).
Otherwise, returns ControlFlow::Break(self < other). Read moreSource§#[doc(hidden)]fn __chaining_le(&self, other: &Rhs) -> ControlFlow<bool>
#[doc(hidden)]fn __chaining_le(&self, other: &Rhs) -> ControlFlow<bool>
partial_ord_chaining_methods)__chaining_lt, but for <= instead of <.Source§#[doc(hidden)]fn __chaining_gt(&self, other: &Rhs) -> ControlFlow<bool>
#[doc(hidden)]fn __chaining_gt(&self, other: &Rhs) -> ControlFlow<bool>
partial_ord_chaining_methods)__chaining_lt, but for > instead of <.Source§#[doc(hidden)]fn __chaining_ge(&self, other: &Rhs) -> ControlFlow<bool>
#[doc(hidden)]fn __chaining_ge(&self, other: &Rhs) -> ControlFlow<bool>
partial_ord_chaining_methods)__chaining_lt, but for >= instead of <.impl TrivialClone for !
Blanket Implementations§
Source§impl<T> BorrowMut<T> for Twhere
T: ?Sized,
impl<T> BorrowMut<T> for Twhere
T: ?Sized,
Source§fn borrow_mut(&mut self) -> &mut T
fn borrow_mut(&mut self) -> &mut T
Source§impl<T> CloneToUninit for Twhere
T: Clone,
impl<T> CloneToUninit for Twhere
T: Clone,
impl<T> Printable for T
Source§impl<T> SizeHint for Twhere
T: ?Sized,
impl<T> SizeHint for Twhere
T: ?Sized,
Source§default fn lower_bound(&self) -> usize
default fn lower_bound(&self) -> usize
core_io_internals)[u8; 12] could return any value between 0 and
12 inclusively as a correct implementation. Read moreSource§impl<T> SizedTypeProperties for T
impl<T> SizedTypeProperties for T
Source§#[doc(hidden)]const SIZE: usize = _
#[doc(hidden)]const SIZE: usize = _
sized_type_properties)Source§#[doc(hidden)]const ALIGN: usize = _
#[doc(hidden)]const ALIGN: usize = _
sized_type_properties)Source§#[doc(hidden)]const ALIGNMENT: Alignment = _
#[doc(hidden)]const ALIGNMENT: Alignment = _
ptr_alignment_type #102070)Source§#[doc(hidden)]const IS_ZST: bool = _
#[doc(hidden)]const IS_ZST: bool = _
sized_type_properties)Source§#[doc(hidden)]const LAYOUT: Layout = _
#[doc(hidden)]const LAYOUT: Layout = _
sized_type_properties)Source§#[doc(hidden)]const MAX_SLICE_LEN: usize = _
#[doc(hidden)]const MAX_SLICE_LEN: usize = _
sized_type_properties)[Self]. Read more