发送特征的终身问题

use*_*625 5 lifetime send rust

我很难理解为什么这段代码无法编译:

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);
}
Run Code Online (Sandbox Code Playgroud)

它给出以下错误:

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
          ...
Run Code Online (Sandbox Code Playgroud)

func()当我尝试约束TSend特征兼容时,问题似乎出现在函数中.没有这个约束,这个代码编译没有错误.

有没有人可以向我解释这种行为的原因是什么?

Vla*_*eev 11

Rust 1.0的更新

在Rust 1.0及更高版本中,示例中的代码(当uints被某些现有类型替换时)失败并出现另一个错误:

% 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`
Run Code Online (Sandbox Code Playgroud)

这有点棘手 - 另一个特点,Sync无处不在.

实现Send特征的类型(尽管其文档当前缺乏,但是可以跨任务边界传输).大多数类型都是Send,但有些类似RcWeak不是Send因为这类类型的实例可能共享非同步的可变状态,因此从多个线程使用是不安全的.

在较旧的Rust版本Send暗示'static,所以引用不是Send.但是,由于Rust 1.0 Send不再暗示'static,因此可以跨线程发送引用.但是,为了&T成为Send,T必须Sync:以下实现需要:

impl<'a, T> Send for &'a T where T: Sync + ?Sized
Run Code Online (Sandbox Code Playgroud)

但是,在我们的情况下,我们不要求&TSend,我们只要求TSend,因此它不应该真正的问题,不是吗?

不.事实上,即使我们没有立即看到它们,仍然参考.请记住,对于Send每个组件必须是一个类型Send,即结构的每个字段,枚举的每个枚举变体的每个部分都必须是Send这个结构/枚举Send.core::cell::Ref内部包含一个实例struct BorrowRef,该实例又包含对它的引用Cell<BorrowFlag>.以下是Sync来自:顺序或&Cell<BorrowFlag>必须Send,Cell<BorrowFlag>必须Sync; 然而,它不是也不可能是Sync因为它提供了不同步的内部可变性.这是错误的实际原因.