【问题标题】:Using a Result by reference if it's Ok如果可以,则通过引用使用结果
【发布时间】:2023-02-17 17:20:34
【问题描述】:

如果设置了某些环境变量,我想更改参数列表。参数列表是一个元组向量,每个元组有两个字符串切片。

应该这样做的代码:

use std::env;

fn main() {
    let mut params = vec![
        // there is a whole list of default params
        ("param", "value"),
    ];

    if let Ok(extra_param) = env::var("EXTRA_PARAM") {
        params.push(("extra_param", &extra_param));
    };

    dbg!(params);
}

当然,它不起作用,因为 extra_params 属于本地 if let 范围,编译器会产生以下错误:

$ EXTRA_PARAM=extra_value cargo run

error[E0597]: `extra_param` does not live long enough
  --> src/main.rs:10:37
   |
10 |         params.push(("extra_param", &extra_param));
   |                                     ^^^^^^^^^^^^ borrowed value does not live long enough
11 |     };
   |     - `extra_param` dropped here while still borrowed
12 |
13 |     dbg!(params);
   |          ------ borrow later used here

For more information about this error, try `rustc --explain E0597`.
error: could not compile `question` due to previous error

我通过在外部作用域中添加一个变量并在引用它之前复制内部变量的值来解决这个问题:

let external_param;

if let Ok(extra_param) = env::var("EXTRA_PARAM") {
    external_param = extra_param;
    params.push(("extra_param", &external_param));
};

现在,我的程序按预期工作,但解决方案感觉平庸。

我错过了什么?有没有什么办法可以得到Result,这样代码就不会那么笨拙了?

我想在不改变元组内部类型的情况下解决这个问题,所以它们仍然是字符串切片,因为它们中有很多是在代码中定义的,我只需要一个额外的参数来有条件地添加。

Rust playground link

【问题讨论】:

  • 是什么明确的params 的类型?是Vec<(&'static str, &'static str)>还是Vec<(&'static str, String)>?或者是其他东西?我认为这会指出你想做什么,而不是你正在做什么。 std::env::var 返回 Result<String, VarError>,所以我想知道你的 Vec 最终包含什么。
  • 它是通过分配 vec![("param", "value")]' 来定义的,所以它只是 Vec<(&str, &str)>。或者至少它是来自 VSCode 的 rust-analyzer 在屏幕上打印的内容。
  • 不要从我所说的中删除生命周期。如果您使用 &str 而不是 String,请务必了解您正在使用的生命周期。如果它是切片,您的向量将一无所有。如果有些是 static lifetime,那很重要。
  • 当您在外部有很多参考而内部参考很少时,这是针对这种情况的完美解决方案。
  • 这是一个很好的解决方案,因为它确实正确地指示了您希望底层 str 存活多长时间。您也可以将 String 泄漏到 &'static str 中,但这意味着它将永远存在,而不是在变量 external_param 的范围内生存,后者更容易控制。

标签: rust


【解决方案1】:

从 cmets 我得到了我的问题,如果我使用外部变量似乎没问题。我发现的唯一更简洁的方法是首先使用unwrap_or_default 提取参数,并将其与条件中的空字符串进行比较:

use std::env;

fn main() {
    let mut params = vec![
        // there is a whole list of default params
        ("param", "value"),
    ];

    let extra_param = env::var("EXTRA_PARAM").unwrap_or_default();

    if extra_param != "" {
        params.push(("extra_param", &extra_param));
    };

    dbg!(params);
}

如果我决定将 params 提取到一个单独的函数中就更有意义了,因为从内部的 Result 中提取值将意味着创建一个局部变量,所以我不能以这种方式返回对参数的引用:

use std::env;

fn main() {
    let extra_param = env::var("EXTRA_PARAM").unwrap_or_default();

    let params = build_params(&extra_param);

    dbg!(params);
}

fn build_params<'a>(extra_param: &'a String) -> Vec<(&'static str, &'a str)> {
    let mut params = vec![
        // there is a whole list of default params
        ("param", "value"),
    ];

    if extra_param != "" {
        params.push(("extra_param", extra_param));
    };

    params
}

【讨论】:

    猜你喜欢
    • 2019-08-22
    • 2019-05-16
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-09-09
    • 1970-01-01
    • 1970-01-01
    • 2012-04-03
    相关资源
    最近更新 更多