gpt4 book ai didi

generics - 将 Arc> 转换为 Arc

转载 作者:行者123 更新时间:2023-12-02 07:57:33 27 4
gpt4 key购买 nike

我正在编写一个带有边和节点的图形实现。该图应同时访问,因此我选择将边和节点构建为 Arc<Mutex<dyn Edge>>Arc<RwLock<dyn Node>> .

不幸的是我得到一个编译错误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());
}
}

playground

但是当我的 T 永远不会成为引用时,为什么我需要终生绑定(bind)? 你问。好吧,Rust 编译器还不知道,一个 T可以是任何类型,包括引用。 T 表示的类型集包括由 &T 表示的类型集和 &mut T .两者 &T&mut TT 的子集.这就是为什么你必须将生命周期限制在 T 上,这是您与编译器沟通的方式,您的 T将只拥有类型或静态引用。

更多关于“静态生命周期”

'static是一生的误导性名称,因为它会让大多数人认为 'static类型必须在程序的整个持续时间内都存在,并且不能动态分配或删除。这些在现实中都不是真的:'static类型可以动态分配,也可以删除。什么'static在实践中真正的意思是“你可以无限期地安全地持有这种类型”。所有“拥有的类型”,如 StringVec'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
}
}

playground

关于生命周期省略和默认特征对象生命周期的更多信息

你定义NodeRefEdgeRef因此:

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如果您想了解更多信息。

你可以缓解 'static通过使您的类型别名在 'a 上通用来满足要求:

pub type NodeRef<'a> = Arc<RwLock<dyn Node + 'a>>;
pub type EdgeRef<'a> = Arc<Mutex<dyn Edge + 'a>>;

然而,这会显着增加代码的复杂性,我敢肯定你想坚持使用 'static因为它已经支持您正在尝试做的事情。

关于generics - 将 Arc<RwLock<T>> 转换为 Arc<RwLock<TraitObject>,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/61712044/

27 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com