问题描述
我一直致力于创建一个 Table
结构,该结构可以解析为 Val
trait 对象以及其他数据类型(Number
作为示例实现),可以在Rust 游乐场 here。我一直无法解决这个借用/生命周期问题,但想法是 Number
和 Table
都是 Val
对象。但是,任何将对象写入 String
缓冲区的尝试都会导致编译失败。
我在这里做错了什么?借用检查器以这种方式运行的理由是什么?
use std::fmt;
use std::fmt::Write;
struct Number(f64);
struct Table<'a> {
rows: Vec<Row<'a>>
// Will have column vector as a member
}
impl <'a>Table<'a> {
fn new(rows: Vec<Vec<Box<dyn Val>>>) -> Table {
let mut table = Table {
rows: rows.into_iter().map(|r| {
Row {
parent: std::ptr::null_mut(),cells: r
}
}).collect()
};
let parent = &mut table as *mut Table;
table.rows = table.rows.into_iter().map(|mut r| {
r.parent = parent;
r
}).collect();
table
}
}
struct Row<'a> {
parent: *mut Table<'a>,cells: Vec<Box<dyn Val<'a>>>
}
impl <'a>Row<'a> {
fn to_str(&'a self,buf: &mut String) -> fmt::Result {
let mut cell_iter = self.cells.iter().enumerate().peekable();
let _parent = unsafe { self.parent.as_ref() }; // Real implementation will need parent ref
while let Some((idx,_c)) = cell_iter.next() { // Real implementation will cycle through columns in parent struct
match self.cells.get(idx) {
Some(v) => v.to_str(buf),None => Ok(())
}?;
if let Some(_) = cell_iter.peek() {
write!(buf,",")?;
}
}
Ok(())
}
}
pub trait Val<'a> {
fn to_str(&'a self,buf: &mut String) -> fmt::Result;
}
pub trait ObjWriter<'a> {
fn to_str(&'a self,buf: &'a mut String) -> fmt::Result;
}
impl <'a>ObjWriter<'a> for dyn Val<'a> {
fn to_str(&'a self,buf: &mut String) -> fmt::Result { self.to_str(buf) }
}
impl <'a>Val<'a> for Table<'a> {
fn to_str(&'a self,buf: &mut String) -> fmt::Result {
write!(buf,"(START TABLE:")?;
let mut row_iter = self.rows.iter().peekable();
while let Some(r) = row_iter.next() {
r.to_str(buf)?;
write!(buf,"\n")?;
}
write!(buf,"END TABLE)")
}
}
impl Number {
fn to_str(&self,"{}",self.0)
}
}
impl <'a>Val<'a> for Number {
fn to_str(&self,buf: &mut String) -> fmt::Result {
self.to_str(buf)
}
}
fn main() {
let table = Table::new(vec![
vec![Box::new(Number(0.5)),Box::new(Table::new(Vec::new()))],vec![Box::new(Table::new(Vec::new())),Box::new(Number(0.5))],]);
let mut buf = String::new();
table.to_str(&mut buf);
println!("{}",buf)
}
error[E0597]: `table` does not live long enough
--> src/main.rs:98:5
|
92 | let table = Table::new(vec![
| ____________________________-
93 | | vec![Box::new(Number(0.5)),94 | | vec![Box::new(Table::new(Vec::new())),95 | | ]);
| |_____- cast requires that `table` is borrowed for `'static`
...
98 | table.to_str(&mut buf);
| ^^^^^ borrowed value does not live long enough
99 | println!("{}",buf)
100 | }
| - `table` dropped here while still borrowed
解决方法
我按照建议的 trentcl 做了,注意到我的指针会在移动时失效,我重构了我的代码,以便任何 Row
方法都将父表的引用作为第一个参数。然后我删除了所有 <'a>
跟随编译器错误,直到它工作。
所以整个问题是允许生命周期失控并使用不安全的方法来获取父引用。去图...