Lifetime issue with submit feature

I am having trouble understanding why this code does not compile:

use std::cell::{Ref, RefCell}; struct St { data: RefCell<uint> } impl St { pub fn test(&self) -> Ref<uint> { self.data.borrow() } } // This code would compile without T constrained to be Send. fn func<T: Send>(_: &T) { } fn main() { let s = St { data: RefCell::new(42) }; { let r7 = s.test(); // Do not compile func(&r7) } // Compile func(&s); } 

It produces the following error:

 bug.rs:21:18: 21:19 error: `s` does not live long enough bug.rs:21 let r7 = s.test(); ^ note: reference must be valid for the static lifetime... bug.rs:17:11: 28:2 note: ...but borrowed value is only valid for the block at 17:10 bug.rs:17 fn main() { bug.rs:18 let s = St { data: RefCell::new(42) }; bug.rs:19 bug.rs:20 { bug.rs:21 let r7 = s.test(); bug.rs:22 // Do not compile ... 

The problem seems to be in the func() function when I try to limit T compatibility with the Send tag. Without this limitation, this code compiles without errors.

Can anyone explain to me what is the reason for this behavior?

+5
source share
2 answers

Update for Rust 1.0

In Rust 1.0 and later, the code in the example (when uint replaced with some existing type) does not execute with another error:

 % rustc test.rs test.rs:23:9: 23:13 error: the trait `core::marker::Sync` is not implemented for the type `core::cell::UnsafeCell<usize>` [E0277] test.rs:23 func(&r7) ^~~~ test.rs:23:9: 23:13 help: run `rustc --explain E0277` to see a detailed explanation test.rs:23:9: 23:13 note: `core::cell::UnsafeCell<usize>` cannot be shared between threads safely test.rs:23:9: 23:13 note: required because it appears within the type `core::cell::Cell<usize>` test.rs:23:9: 23:13 note: required because it appears within the type `core::cell::BorrowRef<'_>` test.rs:23:9: 23:13 note: required because it appears within the type `core::cell::Ref<'_, i32>` test.rs:23:9: 23:13 note: required by `func` 

This is a kind of complexity - another feature, Sync , came out of nowhere.

A type that implements Send trait (although its documentation is certainly not available at the moment) is something that can be passed across task boundaries. Most types of Send , but some, like Rc and Weak , are not Send , because there are instances of such types can share unsynchronized mutable state and therefore it is unsafe to use from multiple threads.

Earlier versions of Rust Send meant 'static , so the links were not Send . However, since Rust 1.0, Send no longer implies 'static , so links can be sent in streams. However, for &T be Send , T must be Sync : this is required in the next implementation

 impl<'a, T> Send for &'a T where T: Sync + ?Sized 

But in our case, we donโ€™t require that &T be Send , we require that T be Send , so that doesnโ€™t matter much, right?

Not. In fact, there are still links, even we do not see them immediately. Remember that for the Send type, each of its components must be Send , that is, each structure field and each part of each enumerated enumeration enumeration must be Send for this structure / enumeration as Send . core::cell::Ref internally contains an instance of struct BorrowRef , which in turn contains a reference to Cell<BorrowFlag> . And this is where Sync comes from: in order, or &Cell<BorrowFlag> to Send , Cell<BorrowFlag> should be Sync ; however, it is not and cannot be Sync , since it provides unsynchronized internal variability. This is the actual cause of the error.

+10
source

According to the Rust link (my highlight):

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

In fact, if you send something to another task, you must guarantee that it will not be destroyed before this other task ends its use, so it cannot belong to the current task.

There are two ways to ensure it:

  • If this object is wholly owned (basically, all members of your structure are also sent).
  • The presence of an object in static storage

So, requiring your function argument to be Send , you need r7 be 'static , but it cannot survive s (as a reference to the contents of RefCell), which isn' t 'static , as defined in your main section.

In general, when writing

 fn foo<T: 'a>(bar: T); 

You need T :

  • A type with all its arguments of life 'a or longer (or without arguments)
  • a &'a reference to type 'a (and you can recursively fulfill these conditions)

And as we saw, T: Send implies T: 'static .

+2
source

Source: https://habr.com/ru/post/1206354/


All Articles