在`return`结尾添加分号会有所不同吗?

时间:2014-10-19 02:10:52

标签: expression rust statements

Rust Guide表示:

  

分号通过丢弃其值并返回单位来将任何表达式转换为语句。

我认为直到我进行实验才得到这个概念:

fn print_number(x: i32, y: i32) -> i32 {
    if x + y > 20 { return x }      
    x + y 
}

编译好。然后,我在返回行的末尾添加了一个分号(return x;)。据我所知,这将该行转换为语句,返回单元数据类型()

尽管如此,最终结果是一样的。

2 个答案:

答案 0 :(得分:4)

通常,if表达式中的每个分支都应具有相同的类型。如果未指定某个分支的类型,则编译器会尝试查找单个公共类型:

fn print_number(x: int, y: int) {
  let v = if x + y > 20 {
    3 // this can be either 3u, 3i, 3u8 etc.
  } else {
    x + y // this is always int
  };
  println!("{}", v);
}

在此代码中,3未指定,但else分支强制其类型为int

这听起来很简单:有一个功能可以统一"两种或多种类型为普通类型,或者在不可能的情况下会给您一个错误。但是如果分支中有fail!怎么办?

fn print_number(x: int, y: int) {
  let v = if x + y > 20 {
    fail!("x + y too large") // ???
  } else {
    x + y // this is always int
  };
  println!("{}", v); // uh wait, what's the type of `v`?
}

我希望fail!不影响其他分支,毕竟这是一个例外情况。由于这种模式在Rust中很常见,因此引入了分歧类型的概念。没有哪种类型有分歧的价值。 (它也被称为"无人居住的类型"或" void类型"取决于上下文。不要与"单位类型&#34混淆;它具有单一值()。由于分歧类型自然是任何其他类型的子集,编译器得出结论:v的类型只是else分支的类型,{{ 1}}。

出于类型检查的目的,

int表达式与Return没有区别。它突然从当前的执行流程中逃脱,就像fail!一样(但幸运的是,并没有终止任务)。不过,分歧类型不会传播到下一个语句:

fail!

请注意,唯一的分号语句fn print_number(x: int, y: int) { let v = if x + y > 20 { return; // this is diverging () // this is implied, even when you omit it } else { x + y // this is always int }; println!("{}", v); // again, what's the type of `v`? } 等同于表达式x;。通常x; ()a; b具有相同的类型,因此b仅在{/ em> {{1}时具有x; () 类型时会非常奇怪没有分歧,并且当()发散时它会发散。这就是为什么你原来的代码没有用的原因。

很有可能添加一个特殊情况:

  • x出现分歧时,为什么不让x分歧?
  • 为什么不对每个未指定的整数文字假设x; ()时无法推断其类型? (注意:过去就是这种情况。)
  • 为什么在统一多个特质对象时不会自动找到常见的超级画面?

事实是,设计类型系统并不是很难,但验证它并不困难,我们希望确保Rust的类型系统具有前瞻性和长期性。其中一些可能会发生,如果它确实有用,并证明"正确"为了我们的目的,但不是立即。

答案 1 :(得分:2)

我不是100%肯定我在说什么,但它有点道理。

还有另一个概念发挥作用:可达性分析。编译器知道return表达式语句后面的内容无法访问。例如,如果我们编译这个函数:

fn test() -> i32 {
    return 1;
    2
}

我们收到以下警告:

warning: unreachable expression
 --> src/main.rs:3:5
  |
3 |     2
  |     ^
  |

如果if表达式以return表达式结束,并且在确定if的类型时仅考虑“false”分支,则编译器可以忽略它的“true”分支表达

您还可以使用diverging functions查看此行为。分散功能是不能正常返回的功能(例如,它们总是失败)。尝试将return表达式替换为fail!宏(扩展为对发散函数的调用)。实际上,return表达式也被认为是分歧的;这是上述可达性分析的基础。

但是,如果()语句后面有实际的return表达式,则会出错。这个功能:

fn print_number(x: i32, y: i32) -> i32 {
    if x + y > 20 {
        return x;
        ()
    } else {
        x + y
    }
}

给出以下错误:

error[E0308]: mismatched types
 --> src/main.rs:4:9
  |
4 |         ()
  |         ^^ expected i32, found ()
  |
  = note: expected type `i32`
             found type `()`

最后,似乎不同的表达式(包括return表达式)在编译器后跟分号时会有不同的处理方式:语句仍然存在分歧。