function - Rust 仅在拆分为多个语句时才编译方法链

标签 function rust compiler-errors compilation method-chaining

遇到此错误时,我正在解析文件中的一些字符串输入。通常,如果将一系列方法链接在一行上或将它们分成多个操作,应该不会有什么不同。然而在这里,当方法链在一行中时,它不会编译。

拆分为多个语句时我没有收到错误 like so (link to playground)

let input = std::fs::read_to_string("tst_input.txt").expect("Failed to read input");
let input = input
    .lines()
    .map(|l| {
        let mut iter = l.split(" | ");
        (
            iter.next()
                .unwrap()
                .split_whitespace()
                .collect::<Vec<&str>>(),
            iter.next()
                .unwrap()
                .split_whitespace()
                .collect::<Vec<&str>>(),
        )
    })
    .collect::<Vec<_>>();

在单个语句中出现生命周期错误 like so (link to playground)

let input = std::fs::read_to_string("tst_input.txt")
    .expect("Failed to read input")
    .lines()
    .map(|l| {
        let mut iter = l.split(" | ");
        (
            iter.next()
                .unwrap()
                .split_whitespace()
                .collect::<Vec<&str>>(),
            iter.next()
                .unwrap()
                .split_whitespace()
                .collect::<Vec<&str>>(),
        )
    })
    .collect::<Vec<_>>()
error[E0716]: temporary value dropped while borrowed
  --> src/main.rs:2:17
   |
2  |       let input = std::fs::read_to_string("tst_input.txt")
   |  _________________^
3  | |         .expect("Failed to read input")
   | |_______________________________________^ creates a temporary which is freed while still in use
...
18 |           .collect::<Vec<_>>();
   |                               - temporary value is freed at the end of this statement
19 |       println!("{:?}", input);
   |                        ----- borrow later used here
   |
   = note: consider using a `let` binding to create a longer lived value

这两种情况应该实际上相同吗?为什么编译器以不同的方式对待它们?这可能是编译器错误吗?

最佳答案

这两种情况并不相同,因为存储的信息不同。

在 Rust 中,变量具有语义含义:它们充当存储信息的地方,更重要的是,它们定义何时销毁此信息 - 这由 Drop trait 处理.默认情况下,drop为超出范围的每个变量调用方法;这可以用 mem::forget 覆盖和一些其他功能,如 Box::into_raw ,但这些都是相当小众的案例。

在第一种情况下,正在读取的数据存储在 inputString 类型的变量.此类型wraps Vec<u8> ,这implements Drop ,因此此数据在 input 时被释放超出范围。然后,第二个input变量 is of type Vec<(Vec<&str>, Vec<&str>)> - 你可以看到它包含一个引用,所以它是从第一个 input 借来的,所以它必须不再是源字符串。在这里,这是令人满意的 - 当然,只要您不尝试将此值返回堆栈,在这种情况下源字符串将被丢弃,并且引用将悬空。

然而,在单行版本中,字符串没有存储在任何地方——它是一个 temporary ,它在语句末尾被销毁。这就是为什么您不允许保留对它的任何引用的原因。但是,您可以通过插入 extra mapping operation 来创建拆分数据的自有版本。 :

let _: Vec<(Vec<String>, Vec<String>)> = std::fs::read_to_string("tst_input.txt")
    .expect("Failed to read input")
    // This iterator borrows from the temporary...
    .lines()
    .map(|l| {
        // ...this iterator reborrows that borrow...
        let mut iter = l.split(" | ");
        (
            iter.next()
                .unwrap()
                .split_whitespace()
                // ...and this operation clones the source data,
                // so they are copied to the new owned location,
                // and not referenced anymore, so can be freely dropped
                .map(str::to_owned)
                .collect::<Vec<_>>(),
            iter.next()
                .unwrap()
                .split_whitespace()
                .map(str::to_owned)
                .collect::<Vec<_>>(),
        )
    })
    .collect::<Vec<_>>();

关于function - Rust 仅在拆分为多个语句时才编译方法链,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/70491691/

相关文章:

ios - 无法调用非函数类型Swift 3的值

c - 双重释放或损坏 (!prev) 中止(核心转储) C 语言错误

c++ - 错误: “Control may reach end of non-void function” in c++

matlab - 从 Matlab 函数返回多个输出变量

c++ - 如何使用 C++ 函数传回一个数字

rust - 将临时 git 依赖项修补到特定版本

rust - 匹配 "if let Some(ref mut x) = option"和 "if let Some(x) = option.as_mut()"中的可变选项引用有什么区别?

rust - 如何解决传递给闭包的 &PathBuf 冲突的生命周期要求?

MySQL:如果我多次在 SQL 查询中使用一个函数,它会每次都重新计算吗?

c - C 中的函数是否有 "type name"?