我正在编写一个函数,它接受一个整数的引用,并返回该整数的向量乘以2,5次 . 我认为这看起来像:
fn foo(x: &i64) -> Vec<&i64> {
let mut v = vec![];
for i in 0..5 {
let q = x * 2;
v.push(&q);
}
v
}
fn main() {
let x = 5;
let q = foo(&x);
println!("{:?}", q);
}
借用检查器变得疯狂,因为我定义了一个新变量,它在堆栈上分配,并在函数末尾超出范围 .
我该怎么办?当然我可以知道 Box
和 Copy
类型的解决方法,但我对一个惯用的Rust解决方案很感兴趣 .
我意识到我可以回复 Vec<i64>
,但我认为会遇到同样的问题?主要试图为一般问题想出一个"emblematic"问题:)
1 回答
编辑:我只是意识到你写了"I'm aware there's Box, Copy etc type workaround but I'm mostly interested in an idiomatic rust solution",但我已经输入了整个答案 . :P下面的解决方案是惯用的Rust,这就是内存的工作原理!不要阻止你,这并不代表任何好事 . ;)
每次返回引用时,该引用必须是函数的参数 . 换句话说,如果要返回对数据的引用,则必须在函数外部分配所有数据 . 你似乎明白这一点,我只是想确保它清楚 . :)
根据您的用例,有许多可能的方法来解决此问题 .
在这个特定的例子中,因为之后你不需要
x
,所以你可以将所有权赋予foo
,而不必费心去参考:但是让's say that you don'想要将所有权转移到
foo
. 只要您不想改变基础值,您仍然可以返回引用向量:...同样,只要您不想发布新的指针,您就可以改变基础值:
......但是,当然,你想要做到这两点 . 因此,如果您正在分配内存并且想要返回它,那么您需要在堆栈之外的其他位置执行此操作 . 你可以做的一件事就是把它放在堆上,使用
Box
:...尽管如此,我只是想确保你知道
Box
是使用堆的一般方法 . 说实话,只需使用Vec
意味着您的数据将被放置在堆上,因此这有效:以上可能是这里最惯用的例子,尽管你的用例可能会要求不同的东西 .
或者,您可以从C的playbook中获取技巧并在
foo
之外预分配内存,然后传入对它的引用:最后,如果函数必须将引用作为参数,并且必须改变引用的数据,并且必须复制引用本身并且必须返回这些复制的引用,那么您可以使用
Cell
:Cell
既高效又不令人惊讶,但请注意Cell
仅适用于实现Copy
特性的类型(所有原始数字类型都可以) . 如果你的类型没有实现Copy
那么你仍然可以使用RefCell
做同样的事情,但它会带来轻微的运行时开销,并且如果你得到_2858285错误,就会在运行时开启恐慌的可能性 .