如何将循环中的变量更新为对循环内创建的值的引用?

时间:2017-01-19 14:55:18

标签: rust lifetime borrow-checker

我想输入一个带有变量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 解决方案。

2 个答案:

答案 0 :(得分:9)

作为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));
}

答案 1 :(得分:4)

如果我理解这一点,问题与循环之外的生活无关; 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分配给具有更长生命周期的变量,但之后您将回到第一个示例。