我很难理解为什么这段代码没有编译:
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);
}
它出现以下错误:
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
...
当我尝试约束func()
与T
特征兼容时,问题似乎出现在函数Send
中。如果没有此约束,此代码将无错误地编译。
是否有人可以向我解释这种行为的原因是什么?
答案 0 :(得分:11)
Rust 1.0的更新
在Rust 1.0及更高版本中,示例中的代码(当uint
被某些现有类型替换时)失败并出现另一个错误:
% 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`
这有点棘手 - 另一个特质Sync
,无处不在。
实现Send
特征的类型(虽然它的文档目前缺乏,但是可以跨任务边界传输)。大多数类型都是Send
,但有些类型(如Rc
和Weak
)不是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
但在我们的情况下,我们并不要求&T
为Send
,我们只要求T
为Send
,所以它不应该真的很重要,对吗?
没有。事实上,仍有是引用,即使我们没有立即看到它们。请记住,对于类型为Send
,其组件必须为Send
,即结构的每个字段和枚举的每个枚举变体的每个部分必须为Send
struct / enum也是Send
。 core::cell::Ref
内部struct BorrowRef
Cell<BorrowFlag>
的实例,Sync
&Cell<BorrowFlag>
的引用Send
。以下是Cell<BorrowFlag>
的来源:按顺序或Sync
为Sync
,{{1}}必须为{{1}};但是,它不是也不能是{{1}},因为它提供了不同步的内部可变性。这是错误的实际原因。
答案 1 :(得分:2)
根据the Rust reference(强调我的):
Send
:可以在任务之间安全地发送此类类型。这种类型包括标量,框,过程和仅包含其他所有类型的结构类型。 所有发送类型均为'static
。
实际上,如果你向其他任务发送了一些东西,你必须保证在其他任务完成使用之前它不会被销毁,所以它不能被当前任务拥有。
有两种方法可以确保它:
因此,通过要求函数的参数为Send
,您需要r7
为'static
,但它不能超过s
(因为它是对'static
的引用RefCell内容),它不是你在主要内容中定义的fn foo<T: 'a>(bar: T);
。
更一般地说,写作时
T
您需要'a
:
&'a
或更长(或没有参数)'a
对类型本身T: Send
的引用(您可以根据这些条件递交)正如我们所见,T: 'static
暗示{{1}}。