简体   繁体   English

如何在 Rust 的闭包内返回对新集合的引用?

[英]How might I return a reference to a new collection inside of a closure in Rust?

I am trying to use a map-like function from an external library that essentially has the following shape:我正在尝试使用来自外部库的类似地图的 function ,该库基本上具有以下形状:

fn map_like<'a, F>(nums: &[usize], f: F) -> Vec<&'a [u8]>
where
    F: Fn(usize) -> &'a [u8],
{
    nums.iter().map(|num| f(*num)).collect()
}

I also have a constant lookup "table":我也有一个不断的查找“表”:

const NAMES: [&str; 4] = ["Ada", "Hal", "Max", "Val"];

and a previously generated array of indices for looking up items in the table:以及先前生成的用于在表中查找项目的索引数组:

let indices: &[usize] = &[0, 3, 1, 2];

I want to use the map-like function to generate an array of "greetings" (as bytes) from the lookup table and the indices.我想使用类似地图的 function 从查找表和索引中生成一个“问候”数组(作为字节)。

I can generate the following trivial "greetings":我可以生成以下琐碎的“问候”:

let greetings: Vec<&[u8]> = map_like(indices, &|i| {
    let name: &str = NAMES[i];
    let greeting: &str = name;
    greeting.as_bytes()
});

// Prints `[[65, 100, 97], [86, 97, 108], [72, 97, 108], [77, 97, 120]]`
println!("{:?}", greetings);

But what I really want to do is format a larger greeting out of each name:但我真正想做的是用每个名字格式化一个更大的问候语:

// Does not compile
let greetings: Vec<&[u8]> = map_like(indices, &|i| {
    let name: &str = NAMES[i];
    let greeting: String = format!("Hello, {}!", name);
    greeting.as_bytes()
});

Unfortunately, the compiler doesn't allow this.不幸的是,编译器不允许这样做。 It throws the following error:它抛出以下错误:

error[E0515]: cannot return reference to local variable `greeting`
  --> src/main.rs:10:9
   |
10 |         greeting.as_bytes()
   |         ^^^^^^^^^^^^^^^^^^^ returns a reference to data owned by the current function

I believe that I even understand what is happening: the format macro is creating a new String that's local to the closure, which as_bytes in turn creates a reference to.我相信我什至了解正在发生的事情: format宏正在创建一个闭包本地的新String ,而as_bytes又创建了一个对它的引用。 Since this new string is deallocated at the end of the closure, this would result in a dangling reference, which the compiler won't allow.由于这个新字符串在闭包结束时被释放,这将导致一个悬空引用,这是编译器不允许的。

Even so, I am at a loss for a workaround.即便如此,我还是不知所措。 I can't come up with a reasonable method for constructing a larger greeting from each name that the compiler is happy with.我想不出一个合理的方法来从编译器满意的每个名称中构造一个更大的问候语。 What is an idiomatic Rust way of approaching this?什么是惯用的 Rust 方法?

Instead of returning references, you should return String with the ownership.您应该返回带有所有权的 String 而不是返回引用。 That is, use String instead of &[u8] like:也就是说,使用String而不是&[u8]像:

fn map_like<F>(nums: &[usize], f: F) -> Vec<String>
where
    F: Fn(usize) -> String,
{
    nums.iter().map(|num| f(*num)).collect()
}

let greetings: Vec<String> = map_like(indices, &|i| {
    let name: &str = NAMES[i];
    let greeting: String = format!("Hello, {}!", name);
    greeting
});

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM