Generics 铸造电弧<;RwLock<;T>&燃气轮机;到弧<;RwLock<;TraitObject>;
我正在编写一个带有边和节点的图形实现。图形应该同时访问,因此我选择将边和节点构建为Generics 铸造电弧<;RwLock<;T>&燃气轮机;到弧<;RwLock<;TraitObject>;,generics,rust,clone,traits,trait-objects,Generics,Rust,Clone,Traits,Trait Objects,我正在编写一个带有边和节点的图形实现。图形应该同时访问,因此我选择将边和节点构建为Arc和Arc 不幸的是,在连接节点/边缘时,我遇到了一个编译错误,参数类型“T”可能活得不够长 pub trait Node { fn connect(&mut self, edge: EdgeRef); } pub type NodeRef = Arc<RwLock<dyn Node>>; pub trait Edge { fn connect(&mut se
Arc
和Arc
不幸的是,在连接节点/边缘时,我遇到了一个编译错误,参数类型“T”可能活得不够长
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());
}
}
pub-trait节点{
fn连接(&mut self,边缘:EdgeRef);
}
pub类型NodeRef=弧;
酒馆特征边缘{
fn connect(&mut self,节点:NodeRef);
}
pub类型EdgeRef=圆弧;
圆弧的impl节点
哪里
T:节点,
{
fn连接(&mut自我,边缘参考:边缘ref){
让mut node=self.write().unwrap();
让mut edge=edge_ref.lock().unwrap();
让self_clone=self.clone()作为NodeRef;//参数类型'T'可能寿命不够长
edge.connect(自克隆);
node.connect(edge_ref.clone());
}
}
问题是:Arc
不应该是引用,因此不应该有生存期。将其强制转换为弧
也不会引入寿命
有人能解释这个编译器错误吗?此问题是否与每个参数化类型(例如,类型
)有关,还是仅与弧
有关?编译错误说明了如何解决此问题:
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`.
但为什么我需要一个终生的约束,而我的T永远不会成为参考?你问。嗯,Rust编译器还不知道,t
可以是任何类型,包括引用。由T
表示的类型集包括由&T
和&mut T
表示的类型集。&T
和&mut T
都是T
的子集。这就是为什么您必须对T
设置生存期限制,这是您与编译器通信的方式,您的T
将仅为所拥有的类型或静态引用
关于“静态寿命”的更多信息
'static
对于生命周期来说是一个误导性的名称,因为它使大多数人认为'static
类型必须在整个程序期间都存在,并且不能动态分配或删除。这两种情况在现实中都不正确:静态类型可以动态分配,也可以删除。实际上,静态的
真正的意思是“您可以安全地无限期地保持这种类型”。所有“自有类型”如String
和Vec
都是静态的
。下面是一个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
}
}
但是,Rust编译器会这样解释:
pub type NodeRef = Arc<RwLock<dyn Node + 'static>>;
pub type EdgeRef = Arc<Mutex<dyn Edge + 'static>>;
但是,这将极大地增加代码的复杂性,我很确定您希望坚持使用'static
,因为它已经支持您尝试执行的操作。类型Arc
可能是一个参考。因为它是一个泛型,T
尚未定义。当您尝试将其与dyn
一起使用时,T
将成为一个参考,尽管与正常参考不完全相同
Rust By Example有一个简单的解释
要解决这个问题,您可以按照编译器的建议将T:Node、
更改为T:Node+'static
,或者您可以将dyn节点
包装在一个文件中。也许我对静态
的理解是错误的(我在上面的帖子中添加了我的理解)。如果是这样的话,你能解释一下为什么以后添加(或删除)的节点可以有一个'static
生存期吗?@CoronA我已经更新了上面的答案,请告诉我是否有用,谢谢。也许这是朝着正确方向迈出的一步。但是我不明白为什么生命周期是一个问题:参数Arc
确保T
的生命周期至少与Arc一样长,因此对Arc>
的强制转换应该推断trait对象的生命周期(对于每个生命周期)。这个想法是错误的还是编译器没有那么聪明?@CoronA如果你删除as NodeRef
cast,你仍然会得到同样的编译器错误,关于T
活得不够长。该问题与将弧
投射到弧
无关。在edge.connect(自我克隆)中有一个隐式强制转换代码>。将此行替换为self.clone().connect(edge\u ref.clone())代码>,它编译(这是无止境的递归,所以只构建它)。对我来说,向特质对象投射似乎是个问题。在我看来,T
不可能是静态的,因为这样的节点可以交互地添加到图形中(可能我的观点是错误的)。关于RefCell
-与RwLock
有什么区别吗?RwLock允许您明确指定线程何时使用数据。所有检查都是在编译期间进行的。RefCell做了类似的事情,但在运行时做。尽管这确实意味着在运行时会有更多的cpu开销。查看更多信息。我的问题不是为了一般的区别——我问的是,考虑到生命周期,这是否会改变任何事情。可能不会。在RwLock
和RefCell
上:看,我认为两者都进行运行时检查。
pub type NodeRef = Arc<RwLock<dyn Node>>;
pub type EdgeRef = Arc<Mutex<dyn Edge>>;
pub type NodeRef = Arc<RwLock<dyn Node + 'static>>;
pub type EdgeRef = Arc<Mutex<dyn Edge + 'static>>;
pub type NodeRef<'a> = Arc<RwLock<dyn Node + 'a>>;
pub type EdgeRef<'a> = Arc<Mutex<dyn Edge + 'a>>;