Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

What does "Box<Fn() + Send + 'static>" mean in rust?

What does Box<Fn() + Send + 'static> mean in rust?

I stumbled upon this syntax while reading advanced types chapter. Send is a trait but what does it mean to + a lifetime to a trait ('static in this case) in type parametrization ? Also what is Fn() ?

like image 291
soupybionics Avatar asked Dec 29 '17 04:12

soupybionics


People also ask

What is rust static?

A static item is similar to a constant, except that it represents a precise memory location in the program. A static is never "inlined" at the usage site, and all references to it refer to the same memory location. Static items have the static lifetime, which outlives all other lifetimes in a Rust program.

What is trait object?

A trait object is an opaque value of another type that implements a set of traits. The set of traits is made up of an object safe base trait plus any number of auto traits. Trait objects implement the base trait, its auto traits, and any supertraits of the base trait.


1 Answers

Let's decompose it one-by-one.

Box

Box<T> is a pointer to heap-allocated T. We use it here because trait objects can only exist behind pointers.

Trait objects

In Box<Fn() + Send + 'static>, Fn() + Send + 'static is a trait object type. In future, it will be written Box<dyn (Fn() + Send + 'static)> to avoid confusion.

Inside dyn are restrictions to the original type. Box<T> can be coerced into Box<Fn() + Send + 'static> only when T: Fn() + Send + 'static. Therefore, although we don't know the original type, we can assume it was Fn() and Send and had 'static lifetime.

Fn()

This is a trait, just like Clone or Default. However, it uses a special syntax sugar.

  • Fn(A1, ..., An) is a syntax sugar for Fn<(A1, ..., An), Output=()>.
  • Fn(A1, ..., An) -> R is a syntax sugar for Fn<(A1, ..., An), Output=R>.
  • This syntax sugar also applies to the following traits: Fn, FnMut, FnOnce, and FnBox.

So what does Fn mean? T: Fn(A1, ..., An) -> R means x: T is a callable object with arguments A1, ..., An and return type R. Examples include function pointers and closures.

Send

Send means that values of this type can be sent across threads. Since this is an auto trait, it can be specified as the second bounds of dyn types (trait object types).

'static bound

In fact, dyn types (trait object types) must have exactly one lifetime bound. It's inferred when omitted. The inference rule is described in RFC 0192 and RFC 1156. It's basically as follows:

  1. If explicitly given, use that lifetime.
  2. Otherwise, it is inferred from the inner trait. For example, Box<Any> is Box<Any + 'static> because Any: 'static.
  3. If the trait doesn't have an appropriate lifetime, it is inferred from the outer type. For example, &'a Fn() is &'a (Fn() + 'a).
  4. If that even failed, it falls back to 'static (for a function signature) or an anonymous lifetime (for a function body).

Conclusion

f: Box<Fn() + Send + 'static> is an owned pointer to a callable value (with the original type unknown and dynamically change) such as closures (with no argument or no return value), which can be sent across threads and lives as long as the program itself.

like image 179
Masaki Hara Avatar answered Sep 17 '22 00:09

Masaki Hara