在 Rust编程语言的Chapter 3中,以下代码用作Rust无法管理的一种类型推断的示例:
fn main() {
let condition = true;
let number = if condition { 5 } else { "six" };
println!("The value of number is: {}", number);
}
解释如下:
Rust需要在编译时知道
number
变量的类型,以便它可以在编译时验证其类型在我们使用number
的任何地方都是有效的。如果number
的类型仅在运行时确定,Rust将无法做到;如果编译器必须跟踪任何变量的多种假设类型,则编译器将更加复杂,并且对代码的保证更少。
我不确定我理解其基本原理,因为该示例确实看起来像一个简单的编译器可以推断类型的事物。
究竟是什么使这种类型推断如此困难?在这种情况下,可以在编译时明确推断出 condition 的值(这是对的),因此数字的类型也可以(i32
?)。
例如,如果您试图在多个编译单元之间推断类型,那么我会发现事情可能会变得变得更加复杂,但是有关此特定示例的内容会增加很多编译器复杂吗?
答案 0 :(得分:9)
我能想到的主要原因有三个:
让我们假设这种语言是这样工作的。由于我们正在扩展类型推断,因此我们还可以使语言更加智能,并使其推断返回类型。这使我可以编写如下内容:
pub fn get_flux_capacitor() {
let is_prod = true;
if is_prod { FluxCapacitor::new() } else { MovieProp::new() }
}
在项目的其他地方,我可以通过调用该函数来获得FluxCapacitor
。但是,有一天,我将is_prod
更改为false
。现在,我不会在我的函数返回错误的类型时出错,而是在每个调用站点上看到错误。一个函数内部的微小更改会导致完全不变的文件中出现错误!真是奇怪。
(如果我们不想添加推断的返回类型,请想象它是一个非常长的函数。)
如果不是那么简单会发生什么?当然,这应该与上面的示例相同:
pub fn get_flux_capacitor() {
let is_prod = (1 + 1) == 2;
...
}
但是这延伸了多远?编译器的常量传播主要是实现细节。您不希望程序中的类型取决于此版本的编译器的智能程度。
当人们看着这段代码时,似乎缺少了一些东西。您为什么要在true
上分支?为什么不只写FluxCapacitor::new()
?可能缺少检查env=DEV
环境变量的逻辑。也许实际上应该使用特征对象,以便您可以利用运行时多态性。
在这种情况下,您要求计算机执行似乎不太正确的操作,Rust经常选择举起手来要求您修复代码。
答案 1 :(得分:2)
您是对的,在这种非常特殊的情况下(静态为condition=true
),可以使编译器能够检测到else
分支不可达,因此number
必须是5。
这只是一个人为的示例,但是...在更一般的情况下,condition
的值只能在运行时动态地知道。
正如其他人所说,就是在这种情况下,推理变得难以实现。
关于该主题,我还没有提到两件事。
在第1点上,Rust处理“此类型可以是多种类型之一”用例的显式方式是enums。 您可以定义如下内容:
#[derive(Debug)]
enum Whatsit {
Num(i32),
Text(&'static str),
}
然后执行let number = if condition { Num(5) } else { Text("six") };
在第2点上,让我们看看枚举(单词间)是该语言中的首选方法。在本书的示例中,我们仅尝试打印number
的值。
在更实际的情况下,我们有时会将number
用于打印以外的其他用途。
这意味着将其传递给另一个函数或将其包含在其他类型中。或者(甚至允许使用println!
)在其上实现Debug
或Display
特征。本地推断意味着(如果您无法在Rust中命名number
的类型),则您将无法执行任何这些操作。
假设您想创建一个对number
做某事的函数;
用您将写的枚举:
fn do_something(number: Whatsit)
但没有它...
fn do_something(number: /* what type is this? */)
简而言之,您说对了,原则上编译器可以为number
合成类型是正确的。例如,编译该代码时,编译器可能会创建一个类似于上面的Whatsit
的匿名枚举。
但是您-程序员-不知道该类型的名称,无法引用它,甚至不知道您可以使用它做什么(我可以将两个“数字”相乘吗?),这将大大限制它的有用性。
遵循类似的方法,例如为语言添加了闭包。编译器会知道闭包具有什么特定类型,但是程序员则不会。如果您有兴趣,我可以尝试查找有关该方法在语言设计中引入的困难的讨论。