Rust Guide表示:
分号通过丢弃其值并返回单位来将任何表达式转换为语句。
我认为直到我进行实验才得到这个概念:
fn print_number(x: i32, y: i32) -> i32 {
if x + y > 20 { return x }
x + y
}
编译好。然后,我在返回行的末尾添加了一个分号(return x;
)。据我所知,这将该行转换为语句,返回单元数据类型()
。
尽管如此,最终结果是一样的。
答案 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
表达式)在编译器后跟分号时会有不同的处理方式:语句仍然存在分歧。