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>>;