将 Arc<RwLock<T>> 转换为 Arc<RwLock<TraitObject>
Cast Arc<RwLock<T>> to Arc<RwLock<TraitObject>
我正在编写一个带有边和节点的图形实现。该图应同时访问,因此我选择将边和节点构建为 Arc<Mutex<dyn Edge>>
和 Arc<RwLock<dyn Node>>
.
不幸的是,我在连接 nodes/edges.
时遇到编译错误 the parameter type 'T' may not live long enough
(Playground)
pub trait Node {
fn connect(&mut self, edge: EdgeRef);
}
pub type NodeRef = Arc<RwLock<dyn Node>>;
pub trait Edge {
fn connect(&mut self, node: NodeRef);
}
pub type EdgeRef = Arc<Mutex<dyn Edge>>;
impl<T> Node for Arc<RwLock<T>>
where
T: Node,
{
fn connect(&mut self, edge_ref: EdgeRef) {
let mut node = self.write().unwrap();
let mut edge = edge_ref.lock().unwrap();
let self_clone = self.clone() as NodeRef; // the parameter type `T` may not live long enough
edge.connect(self_clone);
node.connect(edge_ref.clone());
}
}
问题是:Arc<RwLock<T>>
应该不是引用,所以不应该有生命周期。将其转换为 Arc<RwLock<dyn Node>>
也不会引入生命周期。
有人可以解释这个编译器错误吗?此问题与每个参数类型(例如 Type<T>
)相关还是仅与 Arc<RwLock<T>>
相关?
编译错误说明如何解决问题:
error[E0310]: the parameter type `T` may not live long enough
--> src/lib.rs:22:22
|
15 | impl<T> Node for Arc<RwLock<T>>
| - help: consider adding an explicit lifetime bound...: `T: 'static`
...
22 | let self_clone = self.clone() as NodeRef;
| ^^^^^^^^^^^^
|
note: ...so that the type `T` will meet its required lifetime bounds
--> src/lib.rs:22:22
|
22 | let self_clone = self.clone() as NodeRef;
| ^^^^^^^^^^^^
error: aborting due to previous error
For more information about this error, try `rustc --explain E0310`.
将 + 'static
添加到 T
的边界确实修复了错误:
use std::sync::{Arc, Mutex, RwLock};
pub trait Node {
fn connect(&mut self, edge: EdgeRef);
}
pub type NodeRef = Arc<RwLock<dyn Node>>;
pub trait Edge {
fn connect(&mut self, node: NodeRef);
}
pub type EdgeRef = Arc<Mutex<dyn Edge>>;
impl<T> Node for Arc<RwLock<T>>
where
T: Node + 'static, // added "+ 'static" here
{
fn connect(&mut self, edge_ref: EdgeRef) {
let mut node = self.write().unwrap();
let mut edge = edge_ref.lock().unwrap();
let self_clone = self.clone() as NodeRef;
edge.connect(self_clone);
node.connect(edge_ref.clone());
}
}
但是,当我的 T 永远不会成为参考时,为什么我需要终生绑定? 你问。好吧,Rust 编译器还不知道 T
可以是任何类型,包括引用。 T
表示的类型集包括&T
和&mut T
表示的类型集。 &T
和 &mut T
都是 T
的子集。这就是为什么你必须将生命周期限制在 T
上,这是你与编译器沟通的方式,即你的 T
将仅是拥有类型或静态引用。
有关“静态生命周期”的更多信息
'static
是一个误导性的生命周期名称,因为它使大多数人认为 'static
类型必须在程序的整个持续时间内都存在,并且不能动态分配或删除。这些在现实中都不是真的:'static
类型可以动态分配,也可以删除。 'static
实际上意味着 "you can safely hold on to this type indefinitely"。所有 "owned types" 像 String
和 Vec
都是 'static
。这是一个 Rust 程序,我希望它能说明这一点:
use rand::prelude::*; // 0.7.3
// this function takes 'static types and drops them
// no compiler errors because 'static types can be dynamically allocated and dropped
fn is_static<T: 'static>(t: T) {
std::mem::drop(t)
}
fn main() {
let string = String::from("string"); // dynamically allocated string
is_static(string); // compiles just fine
let mut strings: Vec<String> = Vec::new();
let mut loops = 10;
while loops > 0 {
if rand::random() {
strings.push(format!("randomly dynamically allocated string on loop {}", loops));
}
loops -= 1;
}
// all the strings are 'static
for string in strings {
is_static(string); // compiles no problem
}
}
更多关于生命周期省略和默认特征对象生命周期的信息
你这样定义 NodeRef
和 EdgeRef
:
pub type NodeRef = Arc<RwLock<dyn Node>>;
pub type EdgeRef = Arc<Mutex<dyn Edge>>;
但是 Rust 编译器会这样解释:
pub type NodeRef = Arc<RwLock<dyn Node + 'static>>;
pub type EdgeRef = Arc<Mutex<dyn Edge + 'static>>;
所以当你想将一些 Arc<RwLock<T>>
转换为 NodeRef
时,T
必须受到 Node + 'static
的限制,因为 NodeRef
也有这些限制,即Arc<RwLock<dyn Node + 'static>>
。 Rust 中的所有特征对象都有生命周期,但您通常不会编写它们,因为 Rust 会为您推断它们。 The Rust Reference has a thorough explanation on lifetime elision and default trait object lifetimes 如果您想了解更多。
您可以通过使您的类型别名通用 'a
:
来缓解 'static
要求
pub type NodeRef<'a> = Arc<RwLock<dyn Node + 'a>>;
pub type EdgeRef<'a> = Arc<Mutex<dyn Edge + 'a>>;
然而,这会显着增加代码的复杂性,我敢肯定您想坚持使用 'static
,因为它已经支持您尝试做的事情。
类型 Arc<RwLock<T>>
可能 可能 成为参考。因为它是通用的,所以 T
尚未定义。当您尝试将它与 dyn
一起使用时,T
将成为参考,尽管与普通参考不完全相同。
Rust By Example 有一个简单的解释 here
要解决此问题,您可以按照编译器的建议将 T: Node,
更改为 T: Node + 'static
,或者您可以将 dyn Node
包装在 RefCell
.
中
我正在编写一个带有边和节点的图形实现。该图应同时访问,因此我选择将边和节点构建为 Arc<Mutex<dyn Edge>>
和 Arc<RwLock<dyn Node>>
.
不幸的是,我在连接 nodes/edges.
时遇到编译错误the parameter type 'T' may not live long enough
(Playground)
pub trait Node {
fn connect(&mut self, edge: EdgeRef);
}
pub type NodeRef = Arc<RwLock<dyn Node>>;
pub trait Edge {
fn connect(&mut self, node: NodeRef);
}
pub type EdgeRef = Arc<Mutex<dyn Edge>>;
impl<T> Node for Arc<RwLock<T>>
where
T: Node,
{
fn connect(&mut self, edge_ref: EdgeRef) {
let mut node = self.write().unwrap();
let mut edge = edge_ref.lock().unwrap();
let self_clone = self.clone() as NodeRef; // the parameter type `T` may not live long enough
edge.connect(self_clone);
node.connect(edge_ref.clone());
}
}
问题是:Arc<RwLock<T>>
应该不是引用,所以不应该有生命周期。将其转换为 Arc<RwLock<dyn Node>>
也不会引入生命周期。
有人可以解释这个编译器错误吗?此问题与每个参数类型(例如 Type<T>
)相关还是仅与 Arc<RwLock<T>>
相关?
编译错误说明如何解决问题:
error[E0310]: the parameter type `T` may not live long enough
--> src/lib.rs:22:22
|
15 | impl<T> Node for Arc<RwLock<T>>
| - help: consider adding an explicit lifetime bound...: `T: 'static`
...
22 | let self_clone = self.clone() as NodeRef;
| ^^^^^^^^^^^^
|
note: ...so that the type `T` will meet its required lifetime bounds
--> src/lib.rs:22:22
|
22 | let self_clone = self.clone() as NodeRef;
| ^^^^^^^^^^^^
error: aborting due to previous error
For more information about this error, try `rustc --explain E0310`.
将 + 'static
添加到 T
的边界确实修复了错误:
use std::sync::{Arc, Mutex, RwLock};
pub trait Node {
fn connect(&mut self, edge: EdgeRef);
}
pub type NodeRef = Arc<RwLock<dyn Node>>;
pub trait Edge {
fn connect(&mut self, node: NodeRef);
}
pub type EdgeRef = Arc<Mutex<dyn Edge>>;
impl<T> Node for Arc<RwLock<T>>
where
T: Node + 'static, // added "+ 'static" here
{
fn connect(&mut self, edge_ref: EdgeRef) {
let mut node = self.write().unwrap();
let mut edge = edge_ref.lock().unwrap();
let self_clone = self.clone() as NodeRef;
edge.connect(self_clone);
node.connect(edge_ref.clone());
}
}
但是,当我的 T 永远不会成为参考时,为什么我需要终生绑定? 你问。好吧,Rust 编译器还不知道 T
可以是任何类型,包括引用。 T
表示的类型集包括&T
和&mut T
表示的类型集。 &T
和 &mut T
都是 T
的子集。这就是为什么你必须将生命周期限制在 T
上,这是你与编译器沟通的方式,即你的 T
将仅是拥有类型或静态引用。
有关“静态生命周期”的更多信息
'static
是一个误导性的生命周期名称,因为它使大多数人认为 'static
类型必须在程序的整个持续时间内都存在,并且不能动态分配或删除。这些在现实中都不是真的:'static
类型可以动态分配,也可以删除。 'static
实际上意味着 "you can safely hold on to this type indefinitely"。所有 "owned types" 像 String
和 Vec
都是 'static
。这是一个 Rust 程序,我希望它能说明这一点:
use rand::prelude::*; // 0.7.3
// this function takes 'static types and drops them
// no compiler errors because 'static types can be dynamically allocated and dropped
fn is_static<T: 'static>(t: T) {
std::mem::drop(t)
}
fn main() {
let string = String::from("string"); // dynamically allocated string
is_static(string); // compiles just fine
let mut strings: Vec<String> = Vec::new();
let mut loops = 10;
while loops > 0 {
if rand::random() {
strings.push(format!("randomly dynamically allocated string on loop {}", loops));
}
loops -= 1;
}
// all the strings are 'static
for string in strings {
is_static(string); // compiles no problem
}
}
更多关于生命周期省略和默认特征对象生命周期的信息
你这样定义 NodeRef
和 EdgeRef
:
pub type NodeRef = Arc<RwLock<dyn Node>>;
pub type EdgeRef = Arc<Mutex<dyn Edge>>;
但是 Rust 编译器会这样解释:
pub type NodeRef = Arc<RwLock<dyn Node + 'static>>;
pub type EdgeRef = Arc<Mutex<dyn Edge + 'static>>;
所以当你想将一些 Arc<RwLock<T>>
转换为 NodeRef
时,T
必须受到 Node + 'static
的限制,因为 NodeRef
也有这些限制,即Arc<RwLock<dyn Node + 'static>>
。 Rust 中的所有特征对象都有生命周期,但您通常不会编写它们,因为 Rust 会为您推断它们。 The Rust Reference has a thorough explanation on lifetime elision and default trait object lifetimes 如果您想了解更多。
您可以通过使您的类型别名通用 'a
:
'static
要求
pub type NodeRef<'a> = Arc<RwLock<dyn Node + 'a>>;
pub type EdgeRef<'a> = Arc<Mutex<dyn Edge + 'a>>;
然而,这会显着增加代码的复杂性,我敢肯定您想坚持使用 'static
,因为它已经支持您尝试做的事情。
类型 Arc<RwLock<T>>
可能 可能 成为参考。因为它是通用的,所以 T
尚未定义。当您尝试将它与 dyn
一起使用时,T
将成为参考,尽管与普通参考不完全相同。
Rust By Example 有一个简单的解释 here
要解决此问题,您可以按照编译器的建议将 T: Node,
更改为 T: Node + 'static
,或者您可以将 dyn Node
包装在 RefCell
.