if-statement - 在 Rust 程序中,当条件为 "if"时,会执行 "false"语句,如何理解?

标签 if-statement scope rust borrowing

对于以下 Rust 程序:

fn main() {
    let foo = "test".to_string();
    if false {
        let _bar = foo; // value moved to _bar
    }
    println!("{}", foo);
}

运行时出现这个错误:

error[E0382]: borrow of moved value: `foo`
 --> src\main.rs:6:20
  |
2 |     let foo = "test".to_string();
  |         --- move occurs because `foo` has type `std::string::String`, which does not implement the `Copy` trait
3 |     if false {
4 |         let _bar = foo; // value moved to _bar
  |                    --- value moved here
5 |     }
6 |     println!("{}", foo);
  |                    ^^^ value borrowed here after move

谁能帮忙解释一下这里发生了什么?令我感到奇怪的是,这一举动发生在永远不会为真的 if 语句中。另外我想了解更多关于这种情况,我应该使用哪些关键字来搜索?

最佳答案

这是移动的秘诀:它们实际上并不存在。

移动不会生成与按位复制不同的代码(就机器代码而言)。¹ 移动和复制之间的唯一区别在于“原始”发生了什么:如果它仍然有效,则它是一个副本;如果原件不再有效,那就是一个举动。

那么编译器如何强制您在移动后不使用原始值呢?没有运行时标志来跟踪 foo是否有效。² 相反,编译器在编译时使用源代码分析来确定 foo 是否有效。绝对有效,或者在您尝试使用它时可能已被移出。因为这种分析发生在编译时,它不遵循函数内的执行流程;它立即发生在整个函数中。编译器看到 foo被移出 if ,并拒绝以后使用 foo不评估条件或任何代码。

智能编译器可以在进行有效性分析时考虑控制流,³ 但这可能不是改进。并不总是可以知道是否采用了分支(它是 undecidable ),因此在某些情况下编译器仍然会出错。此外,正如 Cerberus 在问题评论中指出的那样,它会大大减慢编译器的速度。

换句话说:在 Rust 中,你永远不会明确移动某些东西。你想怎么用就怎么用,让编译器根据类型是不是Copy来告诉你是不是做错了。以及以后是否使用。这与 C++ 不同,在 C++ 中,移动是一种可能调用“移动构造函数”并具有副作用的操作;在 Rust 中,它是一个纯静态的通过/失败检查。如果你做对了,程序就会通过并进入下一个编译阶段;如果你做错了,借阅检查员会告诉你(并希望能帮助你解决它)。

也可以看看

  • What are move semantics in Rust?
  • Runtime vs Compile time


  • ¹ 除非移动类型实现 Drop ,在这种情况下,编译器可能会发出 drop flags .

    ² 其实是有(drop flag),但是只有在foo时才检查被丢弃,而不是在每次使用时。未实现的类型 Drop没有放置标志,即使它们具有相同的移动语义。

    ³ 这类似于 Kotlin 中空检查的工作方式:如果编译器可以确定一个引用绝对是非空的,它将允许您取消引用它。 Rust 中的有效性分析比这更保守;编译器甚至不会尝试猜测。

    关于if-statement - 在 Rust 程序中,当条件为 "if"时,会执行 "false"语句,如何理解?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/59222703/

    相关文章:

    C 中的复合条件 : if (0. 0 < a < 1.0)

    serialization - avro-rs解释 `uuid`给出SerdeError

    rust - 参数类型可能不够长(使用线程)

    if-statement - 或内部条件

    html - Django : Could not parse the remainder: '{{' from '{{

    javascript - 对象字面量内的范围

    javascript - 这个变量不应该默认为 "top-level"吗?

    configuration - 以符合人体工程学的方式进行配置处理的 lib

    mysql - 在 cgi-bin/test.pl 使用 "ident"时不允许裸字 "strict subs"

    c++ - 理解 C++ 中的命名空间作用域