【问题标题】:How do I update a variable in a loop to a reference to a value created inside the loop?如何将循环中的变量更新为对循环内创建的值的引用?
【发布时间】:2017-01-19 14:55:17
【问题描述】:

我想进入一个带有变量n 的循环,该变量被函数借用。在每一步,n 都取一个新值;退出循环时,在其他变量的帮助下,工作完成,n永远再次使用。

如果我不使用引用,我有这样的东西:

fn test(n: Thing) -> usize {
    // stuff
    let mut n = n;
    for i in 1..10 {
        let (q, m) = n.do_something(...);
        n = m;
        // stuff with x
    }
    x
}

x 是使用qm 进行一些计算的结果,但它是usize 类型,我在这部分代码中没有遇到任何问题。我没有测试这段代码,但这就是想法。我可以编写这样的代码。

因为我想通过参考来做;我试着写:

fn test(n: &Thing) -> usize {
    // stuff
    let mut n = n;
    for i in 1..10 {
        let (q, m) = (*n).do_something(...);
        n = &m;
        // stuff with x
    }
    x
}

现在代码将无法编译,因为m 的生命周期比n 短。我试图通过做一些棘手的事情或克隆东西来使它工作,但这不是正确的方法。在 C 语言中,代码可以工作,因为我们不关心退出循环时 n 指向的内容,因为在循环之后不使用 n。我完全理解这是 Rust 和 C 不同的地方,但我很确定在 Rust 中存在一种干净的方法。

认为我的问题非常笼统;我不是要求针对特定问题的一些 ad-hoc 解决方案。

【问题讨论】:

    标签: rust lifetime borrow-checker


    【解决方案1】:

    作为Chris Emerson points out,你所做的是不安全,用C编写这样的代码可能也不合适。您引用的变量在每次循环迭代结束时超出范围,因此在下一次迭代开始时您将有一个悬空指针。这将导致 Rust 试图阻止的所有内存错误; Rust 阻止了你做你认为安全的坏事

    如果您想要可以借用或拥有的东西;那是Cow:

    use std::borrow::Cow;
    
    #[derive(Clone)]
    struct Thing;
    
    impl Thing {
        fn do_something(&self) -> (usize, Thing) {
            (1, Thing)
        }
    }
    
    fn test(n: &Thing) -> usize {
        let mut n = Cow::Borrowed(n);
        let mut x = 0;
    
        for _ in 1..10 {
            let (q, m) = n.do_something();
            n = Cow::Owned(m);
            x = x + q;
        }
    
        x
    }
    
    fn main() {
        println!("{}", test(&Thing));
    }
    

    【讨论】:

    • 我同意 Cow 是一个聪明的解决方案,但在这种情况下,我认为只分配给 n(而不是 m)会更简单:play.rust-lang.org/…
    • @Ben 前提是你认为它做了 ^_^。这定义了一个新绑定(这就是let 的含义),因此n 的类型会发生变化,而您永远不会获得新值。看到this version seemingly never increments the value;这就是为什么它(和你的解决方案)抱怨n 是一个未使用的变量。欲了解更多信息,see this other question
    【解决方案2】:

    如果我理解正确,那么问题与循环之外的生活无关; m 的寿命不够长,无法为下一次迭代保留参考。

    let mut n = n;
    for i in 1..10 {
        let (q,m) = (*n).do_something(...)
        n = &m
    }  // At this point m is no longer live, i.e. doesn't live until the next iteration.
    

    同样,它取决于特定的类型/生命周期,但您可能会将 m 分配给生命周期较长的变量,但随后您将回到第一个示例。

    【讨论】:

      猜你喜欢
      • 2011-02-19
      • 1970-01-01
      • 1970-01-01
      • 2011-10-22
      • 1970-01-01
      • 1970-01-01
      • 2021-06-29
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多