嵌套结构:“借来的价值活得不够久”

问题描述

我一直致力于创建一个 Table 结构,该结构可以解析为 Val trait 对象以及其他数据类型(Number 作为示例实现),可以在Rust 游乐场 here。我一直无法解决这个借用/生命周期问题,但想法是 NumberTable 都是 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> 跟随编译器错误,直到它工作。

所以整个问题是允许生命周期失控并使用不安全的方法来获取父引用。去图...