Warning: file_get_contents(/data/phpspider/zhask/data//catemap/7/rust/4.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Rust 如何从函数返回新数据作为引用,而不出现借用检查器问题?_Rust - Fatal编程技术网

Rust 如何从函数返回新数据作为引用,而不出现借用检查器问题?

Rust 如何从函数返回新数据作为引用,而不出现借用检查器问题?,rust,Rust,我正在编写一个函数,它引用一个整数并返回该整数乘以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);

我正在编写一个函数,它引用一个整数并返回该整数乘以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);
}
fn foo(x:&i64)->Vec{
设mut v=vec![];
因为我在0..5{
设q=x*2;
v、 推送(&q);
}
v
}
fn main(){
设x=5;
设q=foo(&x);
println!(“{:?}”,q);
}
借用检查器发疯了,因为我定义了一个新变量,它被分配到堆栈上,并且在函数末尾超出了范围

我该怎么办?当然,如果不编写创建新数据的函数,我就无法度过一生!我知道有
Box
Copy
类型的变通方法,但我对一个惯用的解决方案感兴趣


我意识到我可以返回一个
Vec
,但我认为这会遇到同样的问题?主要是想为一般问题提出一个“象征性”的问题:)

编辑:我刚刚意识到你写了“我知道有框、复制等类型的解决方法,但我主要对惯用的生锈解决方案感兴趣”,但我已经键入了全部答案:P和下面的解决方案都是习惯用法,这就是内存的工作原理!不要试图返回指针到堆栈分配的数据在C或C++中,因为即使编译器没有阻止你,但这并不意味着它会有什么好的结果。p>
无论何时返回引用,该引用都必须是函数的参数。换句话说,如果您返回对数据的引用,那么所有这些数据都必须在函数外部分配。你似乎明白这一点,我只是想确定这是清楚的。:)

根据您的用例,有许多潜在的方法来解决这个问题

在这个特定的示例中,因为您以后不需要
x
做任何事情,所以您可以将所有权授予
foo
,而不必担心引用:

fn foo(x: i64) -> Vec<i64> {
    std::iter::repeat(x * 2).take(5).collect()
}

fn main() {
    let x = 5;
    println!("{:?}", foo(x));
}
…同样,只要您不想向基础值发出新指针,就可以对其进行变异:

fn foo(x: &mut i64) -> &mut i64 {
    *x *= 2;
    x
}

fn main() {
    let mut x = 5;
    println!("{:?}", foo(&mut x));
}
…但当然,你想两者兼而有之。因此,如果您正在分配内存,并且希望返回内存,那么您需要在堆栈之外的其他位置执行此操作。您可以做的一件事就是使用
Box
将其填充到堆中:

// Just for illustration, see the next example for a better approach
fn foo(x: &i64) -> Vec<Box<i64>> {
    std::iter::repeat(Box::new(x * 2)).take(5).collect()
}

fn main() {
    let x = 5;
    println!("{:?}", foo(&x));
}
上面可能是这里最惯用的例子,尽管您的用例可能需要一些不同的东西

或者,您可以从C的playbook中提取一个技巧,在
foo
之外预先分配内存,然后传入对它的引用:

fn foo(x: &i64, v: &mut [i64; 5]) {
    for i in v {
        *i = x * 2;
    }
}

fn main() {
    let x = 5;
    let mut v = [0; 5];  // fixed-size array on the stack
    foo(&x, &mut v);
    println!("{:?}", v);
}
最后,如果函数必须将引用作为其参数,并且必须对引用数据进行变异,并且必须复制引用本身,并且必须返回这些复制的引用,则可以使用
单元格

use std::cell::Cell;

fn foo(x: &Cell<i64>) -> Vec<&Cell<i64>> {
    x.set(x.get() * 2);
    std::iter::repeat(x).take(5).collect()
}

fn main() {
    let x = Cell::new(5);
    println!("{:?}", foo(&x));
}
使用std::cell::cell;
fn foo(x:&Cell)->Vec{
x、 set(x.get()*2);
std::iter::repeat(x).take(5).collect()
}
fn main(){
设x=Cell::new(5);
println!(“{:?}”,foo(&x));
}

Cell
既高效又不足为奇,不过请注意,
Cell
仅适用于实现
Copy
特征的类型(所有基本数字类型都是这样)。如果您的类型没有实现
Copy
,那么您仍然可以使用
RefCell
执行同样的操作,但这会带来轻微的运行时开销,并且如果您的“借用”错误,在运行时可能会出现恐慌。

但我认为这也会遇到同样的问题-您尝试过吗?为什么你认为它会有同样的问题?@Shepmaster我认为如果我在堆栈上的新函数中分配i64,它会生气。但它似乎是有效的。我猜这是因为我把所有权还给了打电话的人,所以借钱人不会感到不安,也就是说,没有借钱?这种解决方案是否比使用包含堆的分配结构(如Box或Cell)更为惯用?正确的是,不涉及借用:在堆栈上分配
i64
s,然后将它们的所有权转移给
Vec
,然后将
Vec
的所有权转移回调用方。与使用包含堆分配的结构相比,更惯用的是-a
Vec
是“包含堆分配的结构”。我想说,在这种情况下使用
Vec
比使用
Box
Cell
更为惯用。在这个特定的示例中,您还可以返回一个数组
[i64;5]
,因为您知道将返回多少个数字。非常感谢。使它更清晰了一百万倍,并且很高兴知道我没有疯!我想这似乎是为了避免像盒子这样的东西,但如果它们没有开销,我想谁会在乎呢?唯一的问题是,返回带有fn内制造的i64的Vec是否会被视为“更惯用”?为了避免堆分配东西?@William,re:
Vec
是最常用的方法,答案是肯定的,我更新了上面的内容以反映这一点。我使用
Box
的示例只是为了确保有很多方法可以使用堆。如果您有一个想要“返回新数据”的函数,并且还没有返回
Vec
,那么您将使用
Box
来代替它。@William,我也不会说
Box
没有开销,因为堆分配比堆栈分配有更多的开销。如果你真的需要最大的性能(但是提防过早的优化等),你应该考虑C风格的方法,你把它传递给在更早的堆栈帧中分配的内存。为了说明这一点,我甚至会更新C风格的示例,使用堆栈分配的数组,而不是
Vec
fn foo(x: &i64, v: &mut [i64; 5]) {
    for i in v {
        *i = x * 2;
    }
}

fn main() {
    let x = 5;
    let mut v = [0; 5];  // fixed-size array on the stack
    foo(&x, &mut v);
    println!("{:?}", v);
}
use std::cell::Cell;

fn foo(x: &Cell<i64>) -> Vec<&Cell<i64>> {
    x.set(x.get() * 2);
    std::iter::repeat(x).take(5).collect()
}

fn main() {
    let x = Cell::new(5);
    println!("{:?}", foo(&x));
}