如何在不使用时有条件地提供默认引用而不执行不必要的计算?

How can I conditionally provide a default reference without performing unnecessary computation when it isn't used?

我有一些变量通过引用传递到我的函数中。我不需要改变它或转移所有权,我只看它的内容。如果内容处于某种状态,我想用默认值替换该值。

例如,我的函数接受 &Vec<String>,如果 Vec 为空,则将其替换为 vec!["empty"]:

fn accept(mut vec: &Vec<String>) {
    if vec.len() == 0 {
        vec = &vec!["empty".to_string()];
    }
    // ... do something with `vec`, like looping over it
}

但这给出了错误:

error[E0716]: temporary value dropped while borrowed
 --> src/lib.rs:3:16
  |
1 | fn accept(mut vec: &Vec<String>) {
  |                    - let's call the lifetime of this reference `'1`
2 |     if vec.len() == 0 {
3 |         vec = &vec!["empty".to_string()];
  |         -------^^^^^^^^^^^^^^^^^^^^^^^^^- temporary value is freed at the end of this statement
  |         |      |
  |         |      creates a temporary which is freed while still in use
  |         assignment requires that borrow lasts for `'1````

阻止 mut 会导致与上一个示例相同的错误:

fn accept(input: &Vec<String>) {
    let vec = if input.len() == 0 {
        &vec!["empty".to_string()]
    } else {
        input
    };
    // ... do something with `vec`, like looping over it
}

我想出的唯一解决方案是提取 if 之外的默认值并引用该值:

fn accept(input: &Vec<String>) {
    let default = vec!["empty".to_string()];
    let vec = if input.len() == 0 {
        &default
    } else {
        input
    };
    // ... do something with `vec`
}

这会导致代码不那么干净并且不必要地进行计算

我知道并理解这个错误...您在 if 正文中借用了默认值,但您借用的那个值在 [=18= 之外并不存在].那不是我的问题。

有没有更简洁的方法来写出这个模式?

我不认为这是 Is there any way to return a reference to a variable created in a function? 的重复,因为我有一个参考,如果可能的话我想使用 first。我不想取消引用引用或 clone() 它,因为 那会执行不必​​要的计算

我可以同时在变量中存储值或引用吗?

如果您不使用默认矢量,则不必创建它。您只需确保声明在 if 块之外完成。

fn accept(input: &Vec<String>) {
    let def;
    let vec = if input.is_empty() {
        def = vec!["empty".to_string()];
        &def
    } else {
        input
    };
    // ... do something with `vec`
}

请注意,您不必在每次收到空向量时都构建一个新的默认向量。您可以在第一次发生这种情况时使用 lazy_static or once_cell:

创建它
#[macro_use]
extern crate lazy_static;

fn accept(input: &[String]) {
    let vec = if input.is_empty() {
        lazy_static! {
            static ref DEFAULT: Vec<String> = vec!["empty".to_string()];
        }
        &DEFAULT
    } else {
        input
    };
    // use vec
}

听起来您可能正在寻找 std::borrow::Cow,具体取决于您将如何使用它。