首页 文章

Value 不够长

提问于
浏览
9

我并不完全了解生命,但我认为 b 的生命将在 self 之前结束 .

那么,如何编辑这段代码呢?我在内存中复制一些东西吗?如果我创建一个新实例,这个生命周期必须遵循这种情况 .

pub struct Formater {
    layout: &'static str,
}

impl Formater {
    pub fn new(layout: &'static str) -> Formater {
        let regex = Regex::new(r"%\{([a-z]+)(?::(.*?[^\\]))?\}").unwrap();
        let b = regex.replace_all(layout, "{}");

        return Formater {
            layout: &b,
        };
    }
}

错误:

error: `b` does not live long enough
  --> src/format.rs:16:22
   |
16 |             layout: &b,
   |                      ^ does not live long enough
17 |         };
18 |     }
   |     - borrowed value only lives until here
   |
   = note: borrowed value must be valid for the static lifetime...

1 回答

  • 8

    b 的范围是 new 函数,因此在函数返回时将释放其内存 . 但是您试图从该函数返回对 b 的引用 . 如果Rust允许您这样做,那么可能使用该引用的唯一代码将在值无效后使用它 . 借用检查器可以保护您免受未定义的行为 .

    使 layout 成为 &'static str 听起来就像是让事情变得简单,但期望来自 regex.replace_all 的动态分配的内存是静态的是不合理的 . 在不进入 unsafe 代码的情况下,您应该将 'static 生命周期中的任何内容视为编译时常量 . 例如,字符串文字 .

    正如其他人所说,你可能希望 layout 成为 String . String 类似于 &str ,但它拥有底层 str . 这意味着当您移动 String 时,基础 str 随之移动 . &str 是一个参考,并且不得超过它所指向的 str 的所有者 .


    如果你真的希望它是 &str ,另一个但不那么符合人体工程学的方法是让 new() 的调用者拥有 &str ,并将其作为可变引用传递给它 .

    pub struct Formatter<'a> {
        layout: &'a str,
    }
    
    impl <'a> Formatter<'a> {
        pub fn new(layout: &'a mut &str) -> Formatter<'a> {
            let regex = Regex::new(r"%\{([a-z]+)(?::(.*?[^\\]))?\}").unwrap();
            *layout = regex.replace_all(layout, "{}");
    
            return Formatter {
                layout: layout,
            };
        }
    }
    

    这会将问题从调用堆栈向上移动一层,这意味着传递给 new 的引用将被 new 突变 .

    pub fn main() {
        let mut s = "blah %{blah}";
        {
            let formatter = Formatter::new(&mut s);
            println!("{:?}", formatter.layout); // "blah {}"
        }
        println!("{:?}", s); // "blah {}"
    }
    

    现在 smain 所有,因此 formatter 只要在比 main 更小的范围内使用 formatter 就有效 .

    但总的来说,我认为这种方法比较麻烦,除非你有充分的理由,否则你应该坚持使用 String .

相关问题