当尝试在结构体之间移动借用的数据时,我遇到了生存期问题。在高层次上,我想做一些类似的事情:
- 读取一个yml文件到字符串缓冲区
- 使用
from_str
将其转换为结构体 - 从相同的借用数据创建不同的结构
- 把它写进一个文件里
下面是我构建的给出生存期错误的示例实现:
Rust playground link
use serde::{Serialize, Deserialize};
#[derive(Deserialize, Debug, Serialize)]
pub struct Foo<'a> {
name: &'a str
}
impl<'a> Foo<'a> {
pub fn new(name: &'a str) -> Self {
Self { name }
}
}
#[derive(Deserialize, Debug, Serialize)]
pub struct Bar<'a> {
name: &'a str
}
impl<'a> Bar<'a> {
pub fn new(name: &'a str) -> Self {
Self { name }
}
}
pub trait Visitor {
type Value;
fn visit_table_borrowed<'a>(&mut self, t: &'a Foo<'a>) {
let _ = t;
}
}
pub trait DataBorrowed {
fn accept<V: Visitor>(&self, visitor: &mut V);
}
impl<'a> DataBorrowed for Foo<'a> {
fn accept<V: Visitor>(&self, visitor: &mut V) {
visitor.visit_table_borrowed(self)
}
}
impl<'a> Visitor for Bar<'a> {
type Value = Bar<'a>;
fn visit_table_borrowed(&mut self, t: &'a Foo<'a>) {
self.name = t.name;
}
}
impl<'a> From<Foo<'a>> for Bar<'a> {
fn from(dt: Foo<'a>) -> Self {
let mut table = Bar::new("bar");
dt.accept(&mut table);
table
}
}
fn main() {
let f = Foo::new("foo");
let b: Bar = Bar::from(f);
}
字符串
错误:
error[E0308]: method not compatible with trait
--> src/main.rs:49:5
|
49 | fn visit_table_borrowed(&mut self, t: &'a Foo<'a>) {
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ lifetime mismatch
|
= note: expected signature `fn(&mut Bar<'a>, &'a Foo<'a>)`
found signature `fn(&mut Bar<'a>, &'a Foo<'a>)`
note: the lifetime `'a` as defined here...
--> src/main.rs:49:5
|
49 | fn visit_table_borrowed(&mut self, t: &'a Foo<'a>) {
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
note: ...does not necessarily outlive the lifetime `'a` as defined here
--> src/main.rs:47:6
|
47 | impl<'a> Visitor for Bar<'a> {
| ^^
For more information about this error, try `rustc --explain E0308`.
型
1条答案
按热度按时间sczxawaw1#
代码的第一个问题是trait定义和实际实现的签名不匹配,一个方法有生命周期参数,另一个没有,这是编译器抱怨的。
要解决这个问题,你可以仔细检查两个方法是否有相同的签名(我个人总是从trait的定义中复制并粘贴签名,或者让LSP服务器为我做这件事)。
还有一个问题是
&'a Foo<'a>
实际上是一种代码气味,它实际上从来都不是实际的生存期,只有在少数情况下是可以的。除非你知道你在做什么,否则你应该总是从每个生存期漏洞的不同生存期开始,这样编译器就可以告诉你它认为这些生存期是如何联系的。实际上,您并不希望您的借用受到对
Foo
的引用的限制,毕竟您希望从它移动引用并使用更长的生存期,但是如果您人为地强制&'a Foo<'b>
的'a
和'b
相同,通过重用'a
作为内部生存期,这是不可能的。要解决这个问题,请在所有地方将
&'a Foo<'a>
替换为&Foo<'a>
(可以在使用它的所有地方省略外部生存期)第三个问题是,你的trait定义不允许你的需求,你不能让一个函数在生命周期内是泛型的,同时将同一生命周期固定为实现的某个生命周期。
要修复它,请更改
Visitor
和DataBorrowed
以接受生命周期参数:字符串
下面是一个完整的版本,解决了所有三个问题:
型