简体   繁体   中英

What is the difference between Send and 'static on a closure in rust?

Consider these structs:

struct Promise1<T, Err> {
    on_resolve:Option<|promised:T|: Send>,
    on_reject:Option<|failed:Err|: Send>,
}

struct Promise2<T, Err> {
    on_resolve:Option<|promised:T|: 'static>,
    on_reject:Option<|failed:Err|: 'static>,
}

struct Promise3<'a, T, Err> {
    on_resolve:Option<|promised:T|: 'a>,
    on_reject:Option<|failed:Err|: 'a>,
}

Tangibly, what is the difference between them?

What is 'Send' as a bound, and why when providing Send, do I no longer have to provide a lifetime? What is this implicit lifetime that Send is generating?

Specifically, what is the difference between Send and 'static as closure bounds.

For example, this works:

let k:|int|:Send = |i:int| {};
let p:|int|:Send = |i:int| {};
Promise1 {
    on_resolve:Some(k),
    on_reject:Some(p)
};

But this does not:

let k = |i:int| {};
let p = |i:int| {};
Promise1 {
    on_resolve:Some(k),
    on_reject:Some(p)
};

Error:

error: mismatched types: expected `core::option::Option<'static |_|:Send>`, found 
`core::option::Option<|int|>` (expected bounds `Send`, found no bounds)

...however, this works fine using Promise2 or Promise3 with 'static and 'a respectively.

Send is a 'kind' http://doc.rust-lang.org/reference.html#built-in-traits

send : Able to be sent across task boundaries.

'static is a lifetime that's special: a lifetime that lasts for the entire program.

The reference also contains another illuminating section on Send : (we haven't gotten an optimal layout for the reference yet) http://doc.rust-lang.org/reference.html#type-kinds

Send : Types of this kind can be safely sent between tasks. This kind includes scalars, boxes, procs, and structural types containing only other owned types. All Send types are 'static.

So that's why you can use them interchangeably in certain situations.

Why are we talking about a lifetime?

A closure embeds an environment, which may or not contain references to the current thread stack. This environment has a lifetime bound, which indicates the maximum duration for which it is viable and corresponds to the shortest lifetime of any embedded reference, which you indicate with the appropriate notation.

  • if it contains a reference to the current thread stack, then the lifetime of the closure should not exceed the lifetime of said reference
  • if it contains a reference to a static resource, and is not linked to the thread stack thus, then the lifetime of the closure is not limited

'static is the upper bound, since it gives no restriction, and therefore 'static is used to indicate the absence of any lifetime constraint. It neatly avoid a special case: there is always a lifetime bound, it is just that sometimes it's "infinite".

What does Send mean?

The Send kind is applied to an object to indicate it can be sent to another thread safely, for example via a channel. It implies, thus, that said object carries no reference to the current thread stack, as otherwise should the stack unwind the object would contain dangling references!

Why does Send seem to imply 'static ?

  1. If an object has no reference to the current stack, its lifetime bound is 'static
  2. Send implies that an object has no reference to the current stack

It is trivial, therefore, that Send implies the lifetime bound of the object is 'static .

But...

There are actually safe ways to refer to another stack's reference, for example in fork-join parallelism where the thread being referred to ensures it outlives the threads borrowing references. It was touched on here , and seem to require different kinds than Send to precisely specify how the data can be safely shared.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM