[go: up one dir, main page]

Primitive Type never

๐Ÿ”ฌThis is a nightly-only experimental API. (never_type #35121)
Expand description

The ! type, also called โ€œneverโ€.

! represents the type of computations which never resolve to any value at all. For example, the exit function fn exit(code: i32) -> ! exits the process without ever returning, and so returns !.

break, continue and return expressions also have type !. For example we are allowed to write:

#![feature(never_type)]
let x: ! = {
    return 123
};

Although the let is pointless here, it illustrates the meaning of !. Since x is never assigned a value (because return returns from the entire function), x can be given type !. We could also replace return 123 with a panic! or a never-ending loop and this code would still be valid.

A more realistic usage of ! is in this code:

let num: u32 = match get_a_number() {
    Some(num) => num,
    None => break,
};

Both match arms must produce values of type u32, but since break never produces a value at all we know it can never produce a value which isnโ€™t a u32. This illustrates another behavior of the ! type - expressions with type ! will coerce into any other type.

ยง! and generics

ยงInfallible errors

The main place youโ€™ll see ! used explicitly is in generic code. Consider the FromStr trait:

trait FromStr: Sized {
    type Err;
    fn from_str(s: &str) -> Result<Self, Self::Err>;
}

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, the appropriate type is !. (Currently the type actually used is an enum with no variants, though this is only because ! was added to Rust at a later date and it may change in the future.) With an Err type of !, if we have to call String::from_str for some reason the result will be a Result<String, !> which we can unpack like this:

use std::str::FromStr;
let Ok(s) = String::from_str("hello");

Since the Err variant contains a !, it can never occur. This means we can exhaustively match on Result<T, !> by just taking the Ok variant. This illustrates another behavior of ! - it can be used to โ€œdeleteโ€ certain enum variants from generic types like Result.

ยงInfinite loops

While Result<T, !> is very useful for removing errors, ! can also be used to remove successes as well. If we think of Result<T, !> as โ€œif this function returns, it has not errored,โ€ we get a very intuitive idea of Result<!, E> as well: if the function returns, it has errored.

For example, consider the case of a simple web server, which can be simplified to:

โ“˜
loop {
    let (client, request) = get_request().expect("disconnected");
    let response = request.process();
    response.send(client);
}

Currently, this isnโ€™t ideal, because we simply panic whenever we fail to get a new connection. Instead, weโ€™d like to keep track of this error, like this:

โ“˜
loop {
    match get_request() {
        Err(err) => break err,
        Ok((client, request)) => {
            let response = request.process();
            response.send(client);
        },
    }
}

Now, when the server disconnects, we exit the loop with an error instead of panicking. While it might be intuitive to simply return the error, we might want to wrap it in a Result<!, E> instead:

โ“˜
fn server_loop() -> Result<!, ConnectionError> {
    loop {
        let (client, request) = get_request()?;
        let response = request.process();
        response.send(client);
    }
}

Now, we can use ? instead of match, and the return type makes a lot more sense: if the loop ever stops, it means that an error occurred. We donโ€™t even have to wrap the loop in an Ok because ! coerces to Result<!, ConnectionError> automatically.

ยง! and traits

When writing your own traits, ! should have an impl whenever there is an obvious impl which doesnโ€™t panic!. The reason is that functions returning an impl Trait where ! does not have an impl of Trait cannot diverge as their only possible code path. In other words, they canโ€™t return ! from every code path. As an example, this code doesnโ€™t compile:

โ“˜
use std::ops::Add;

fn foo() -> impl Add<u32> {
    unimplemented!()
}

But this code does:

use std::ops::Add;

fn foo() -> impl Add<u32> {
    if true {
        unimplemented!()
    } else {
        0
    }
}

The reason is that, in the first example, there are many possible types that ! could coerce to, because many types implement Add<u32>. However, in the second example, the else branch returns a 0, which the compiler infers from the return type to be of type u32. Since u32 is a concrete type, ! can and will be coerced to it. See issue #36375 for more information on this quirk of !.

As it turns out, though, most traits can have an impl for !. Take Debug for example:

#![feature(never_type)]
impl Debug for ! {
    fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
        *self
    }
}

Once again weโ€™re using !โ€™s ability to coerce into any other type, in this case fmt::Result. Since this method takes a &! as an argument we know that it can never be called (because there is no value of type ! for it to be called with). Writing *self essentially tells the compiler โ€œWe know that this code can never be run, so just treat the entire function body as having type fmt::Resultโ€. This pattern can be used a lot when implementing traits for !. Generally, any trait which only has methods which take a self parameter should have such an impl.

On the other hand, one trait which would not be appropriate to implement is Default:

trait Default {
    fn default() -> Self;
}

Since ! has no values, it has no default value either. Itโ€™s true that we could write an impl for this which simply panics, but the same is true for any type (we could impl Default for (eg.) File by just making default() panic.)

ยงNever type fallback

When the compiler sees a value of type ! in a coercion site, it implicitly inserts a coercion to allow the type checker to infer any type:

โ“˜
// this
let x: u8 = panic!();

// is (essentially) turned by the compiler into
let x: u8 = absurd(panic!());

// where absurd is a function with the following signature
// (it's sound, because `!` always marks unreachable code):
fn absurd<T>(_: !) -> T { ... }

This can lead to compilation errors if the type cannot be inferred:

โ“˜
// this
{ panic!() };

// gets turned into this
{ absurd(panic!()) }; // error: can't infer the type of `absurd`

To prevent such errors, the compiler remembers where it inserted absurd calls, and if it canโ€™t infer the type, it uses the fallback type instead:

โ“˜
type Fallback = /* An arbitrarily selected type! */;
{ absurd::<Fallback>(panic!()) }

This is what is known as โ€œnever type fallbackโ€.

Historically, the fallback type was (), causing confusing behavior where ! spontaneously coerced to (), even when it would not infer () without the fallback. The fallback was changed to ! in the 2024 edition, and will be changed in all editions at a later date.

Trait Implementationsยง

Sourceยง

impl Clone for !

Sourceยง

fn clone(&self) -> !

Returns a duplicate of the value. Read more
1.0.0 ยท Sourceยง

fn clone_from(&mut self, source: &Self)

Performs copy-assignment from source. Read more
Sourceยง

impl Debug for !

Sourceยง

fn fmt(&self, _: &mut Formatter<'_>) -> Result<(), Error>

Formats the value using the given formatter. Read more
Sourceยง

impl Display for !

Sourceยง

fn fmt(&self, _: &mut Formatter<'_>) -> Result<(), Error>

Formats the value using the given formatter. Read more
Sourceยง

impl Error for !

1.30.0 ยท Sourceยง

fn source(&self) -> Option<&(dyn Error + 'static)>

Returns the lower-level source of this error, if any. Read more
1.0.0 ยท Sourceยง

fn description(&self) -> &str

๐Ÿ‘ŽDeprecated since 1.42.0: use the Display impl or to_string()
1.0.0 ยท Sourceยง

fn cause(&self) -> Option<&dyn Error>

๐Ÿ‘ŽDeprecated since 1.33.0: replaced by Error::source, which can support downcasting
Sourceยง

fn provide<'a>(&'a self, request: &mut Request<'a>)

๐Ÿ”ฌThis is a nightly-only experimental API. (error_generic_member_access #99301)
Provides type-based access to context intended for error reports. Read more
1.34.0 (const: unstable) ยท Sourceยง

impl From<!> for Infallible

Sourceยง

fn from(x: !) -> Infallible

Converts to this type from the input type.
Sourceยง

impl From<!> for TryFromIntError

Sourceยง

fn from(never: !) -> TryFromIntError

Converts to this type from the input type.
1.29.0 ยท Sourceยง

impl Hash for !

Sourceยง

fn hash<H>(&self, _: &mut H)
where H: Hasher,

Feeds this value into the given Hasher. Read more
1.3.0 ยท Sourceยง

fn hash_slice<H>(data: &[Self], state: &mut H)
where H: Hasher, Self: Sized,

Feeds a slice of this type into the given Hasher. Read more
1.60.0 ยท Sourceยง

impl Not for !

Sourceยง

type Output = !

The resulting type after applying the ! operator.
Sourceยง

fn not(self) -> !

Performs the unary ! operation. Read more
Sourceยง

impl Ord for !

Sourceยง

fn cmp(&self, _: &!) -> Ordering

This method returns an Ordering between self and other. Read more
1.21.0 ยท Sourceยง

fn max(self, other: Self) -> Self
where Self: Sized,

Compares and returns the maximum of two values. Read more
1.21.0 ยท Sourceยง

fn min(self, other: Self) -> Self
where Self: Sized,

Compares and returns the minimum of two values. Read more
1.50.0 ยท Sourceยง

fn clamp(self, min: Self, max: Self) -> Self
where Self: Sized,

Restrict a value to a certain interval. Read more
Sourceยง

impl PartialEq for !

Sourceยง

fn eq(&self, _: &!) -> bool

Tests for self and other values to be equal, and is used by ==.
1.0.0 ยท Sourceยง

fn ne(&self, other: &Rhs) -> bool

Tests for !=. The default implementation is almost always sufficient, and should not be overridden without very good reason.
Sourceยง

impl PartialOrd for !

Sourceยง

fn partial_cmp(&self, _: &!) -> Option<Ordering>

This method returns an ordering between self and other values if one exists. Read more
1.0.0 ยท Sourceยง

fn lt(&self, other: &Rhs) -> bool

Tests less than (for self and other) and is used by the < operator. Read more
1.0.0 ยท Sourceยง

fn le(&self, other: &Rhs) -> bool

Tests less than or equal to (for self and other) and is used by the <= operator. Read more
1.0.0 ยท Sourceยง

fn gt(&self, other: &Rhs) -> bool

Tests greater than (for self and other) and is used by the > operator. Read more
1.0.0 ยท Sourceยง

fn ge(&self, other: &Rhs) -> bool

Tests greater than or equal to (for self and other) and is used by the >= operator. Read more
1.61.0 ยท Sourceยง

impl Termination for !

Sourceยง

fn report(self) -> ExitCode

Is called to get the representation of the value as status code. This status code is returned to the operating system.
Sourceยง

impl Copy for !

Sourceยง

impl Eq for !

Auto Trait Implementationsยง

ยง

impl Freeze for !

ยง

impl RefUnwindSafe for !

ยง

impl Send for !

ยง

impl Sync for !

ยง

impl Unpin for !

ยง

impl UnwindSafe for !

Blanket Implementationsยง

Sourceยง

impl<T> Any for T
where T: 'static + ?Sized,

Sourceยง

fn type_id(&self) -> TypeId

Gets the TypeId of self. Read more
Sourceยง

impl<T> Borrow<T> for T
where T: ?Sized,

Sourceยง

fn borrow(&self) -> &T

Immutably borrows from an owned value. Read more
Sourceยง

impl<T> BorrowMut<T> for T
where T: ?Sized,

Sourceยง

fn borrow_mut(&mut self) -> &mut T

Mutably borrows from an owned value. Read more
Sourceยง

impl<T> CloneToUninit for T
where T: Clone,

Sourceยง

unsafe fn clone_to_uninit(&self, dest: *mut u8)

๐Ÿ”ฌThis is a nightly-only experimental API. (clone_to_uninit #126799)
Performs copy-assignment from self to dest. Read more
Sourceยง

impl<T> From<!> for T

Sourceยง

fn from(t: !) -> T

Converts to this type from the input type.
Sourceยง

impl<T> From<T> for T

Sourceยง

fn from(t: T) -> T

Returns the argument unchanged.

Sourceยง

impl<T, U> Into<U> for T
where U: From<T>,

Sourceยง

fn into(self) -> U

Calls U::from(self).

That is, this conversion is whatever the implementation of From<T> for U chooses to do.

Sourceยง

impl<T> ToOwned for T
where T: Clone,

Sourceยง

type Owned = T

The resulting type after obtaining ownership.
Sourceยง

fn to_owned(&self) -> T

Creates owned data from borrowed data, usually by cloning. Read more
Sourceยง

fn clone_into(&self, target: &mut T)

Uses borrowed data to replace owned data, usually by cloning. Read more
Sourceยง

impl<T> ToString for T
where T: Display + ?Sized,

Sourceยง

fn to_string(&self) -> String

Converts the given value to a String. Read more
Sourceยง

impl<T, U> TryFrom<U> for T
where U: Into<T>,

Sourceยง

type Error = Infallible

The type returned in the event of a conversion error.
Sourceยง

fn try_from(value: U) -> Result<T, <T as TryFrom<U>>::Error>

Performs the conversion.
Sourceยง

impl<T, U> TryInto<U> for T
where U: TryFrom<T>,

Sourceยง

type Error = <U as TryFrom<T>>::Error

The type returned in the event of a conversion error.
Sourceยง

fn try_into(self) -> Result<U, <U as TryFrom<T>>::Error>

Performs the conversion.