无法从函数返回命令行ARG



我正在尝试制作一个简单的函数以返回命令行参数。代码看起来像这样:

use std::env;
fn main() {
    let (query, filename) = parse();
}
fn parse() -> (&str, &str) {
    let args: Vec<String> = env::args().collect();
    let query = args[1];
    let filename = args[2];
    return (query, filename)
}

但是它不会编译,错误看起来像这样:

error[E0106]: missing lifetime specifier
  --> src/main.rs:15:22
   |
15 | fn parse() -> (&str, &str) {
   |                      ^ help: consider giving it a 'static lifetime: `&'static`
   |
   = help: this function's return type contains a borrowed value, but there is no value for it to be borrowed from

这表明我需要在函数声明中添加 &'static,例如:

fn parse() -> (&'static str, &'static str) {

但这也不起作用;

error[E0308]: mismatched types
  --> src/main.rs:20:13
   |
20 |     return (query, filename)
   |             ^^^^^
   |             |
   |             expected reference, found struct `std::string::String`
   |             help: consider borrowing here: `&query`
   |
   = note: expected type `&'static str`
              found type `std::string::String`
error[E0308]: mismatched types
  --> src/main.rs:20:20
   |
20 |     return (query, filename)
   |                    ^^^^^^^^
   |                    |
   |                    expected reference, found struct `std::string::String`
   |                    help: consider borrowing here: `&filename`
   |
   = note: expected type `&'static str`
              found type `std::string::String`

它说我需要添加借款,这样:

return (&query, &filename)

但这也不起作用;

warning: unused variable: `query`
 --> src/main.rs:5:10
  |
5 |     let (query, filename) = parse();
  |          ^^^^^ help: consider prefixing with an underscore: `_query`
  |
  = note: #[warn(unused_variables)] on by default
warning: unused variable: `filename`
 --> src/main.rs:5:17
  |
5 |     let (query, filename) = parse();
  |                 ^^^^^^^^ help: consider prefixing with an underscore: `_filename`
error[E0507]: cannot move out of borrowed content
  --> src/main.rs:17:17
   |
17 |     let query = args[1];
   |                 ^^^^^^^
   |                 |
   |                 cannot move out of borrowed content
   |                 help: consider borrowing here: `&args[1]`
error[E0507]: cannot move out of borrowed content
  --> src/main.rs:18:20
   |
18 |     let filename = args[2];
   |                    ^^^^^^^
   |                    |
   |                    cannot move out of borrowed content
   |                    help: consider borrowing here: `&args[2]`
error[E0515]: cannot return value referencing local variable `filename`
  --> src/main.rs:20:12
   |
20 |     return (&query, &filename)
   |            ^^^^^^^^^---------^
   |            |        |
   |            |        `filename` is borrowed here
   |            returns a value referencing data owned by the current function
error[E0515]: cannot return value referencing local variable `query`
  --> src/main.rs:20:12
   |
20 |     return (&query, &filename)
   |            ^------^^^^^^^^^^^^
   |            ||
   |            |`query` is borrowed here
   |            returns a value referencing data owned by the current function

不知道发生了什么或为什么它不起作用,我也直接从教程中复制了示例。

字符串在Rust中很棘手。首先,让我们回顾"什么是所有权?","切片类型"one_answers"终身语法"。

问题是&str是对象的借用(由&表示(。生锈的编译器需要知道将借用多长时间。现在,Rust实际上将尝试通过假设返回值的寿命与输入值的寿命相匹配,但在这种情况下,它无法推断出输入值,因此Rust将尝试"生命周期"。它需要您用寿命注释返回类型。您 can 使用'static,但您也可以为您的函数提供通用的寿命指定符。这是一个简化的示例:

Rust Playground

fn main() {
    println!("{}", gimme_str());
}
fn gimme_str() -> &str {
    return "foo";
}

也不会编译。但是,您需要做的才能使其编译为添加一生,例如:

使用Lifetime Specifier

fn main() {
    println!("{}", gimme_str());
}
fn gimme_str<'a>() -> &'a str {
    return "foo";
}

另外,您可以从输入中推断出寿命,尽管在这种情况下,由于输入未使用,这很奇怪:

使用生命周期(从输入推断(

fn main() {
    println!("{}", gimme_str("bar"));
}
fn gimme_str(_input: &str) -> &str {
    return "foo";
}

,这就是寿命指示符。但是您还有另一个问题,即您的返回值是该功能拥有的字符串片。我们可以通过修改先前的Rust Playground代码(具有寿命指示符(:

来证明简化形式的错误:

不能借用本地变量

fn main() {
    println!("{}", gimme_str());
}
fn gimme_str<'a>() -> &'a str {
    let foo = String::from("foo");
    return &foo;
}

借用始终是某物的借用。在上一个示例代码中,我使用字符串字面的代码, &str不可变的字符串文字的借用。这是编译器生成的Rust二进制文件的一部分,&str可以指向二进制的那一部分。您可以将基本记忆视为二进制本身"拥有"的基础记忆,这意味着它永远不会超出范围(即字符串字面的寿命为 'static(。

但是,在修改后的示例中, &foo不是字符串文字,而是 String对象的借用。该String对象分配给本地变量,因此其所有者是该变量的所有者 - 函数。这意味着当功能退出时,它将脱离范围并删除。但是一旦String对象不再存在,借用它就无效。

为了使String的生活在功能范围之外,我们必须返回String本身,以便将所有权转移给呼叫者。我们不能仅仅退还借钱。请参阅示例代码:

从功能转移所有权

fn main() {
    println!("{}", gimme_str());
}
fn gimme_str() -> String {
    let foo = String::from("foo");
    return foo;
}

要将其应用于您的情况,您将必须从功能中返回String,而不是&str

最新更新