我的问题是关于奥德斯基的讲座3.5(不是作业!):
19:15的练习问:“if (true) 1 else false
”是什么类型的
在他的解释中,Odersky认为类型是AnyVal
,因为它是Int
和Boolean
(两个条件分支的类型)中最具体的超类型。
我问自己为什么类型检查器不够聪明,只能看到第一个分支实际上是相关的,因此可以将类型推断为Int
?
答案 0 :(得分:11)
这是一个类似的问题,为什么以下不能用Java编译:
throw new Foo();
return 42; //unreachable statement
但这会编译:
if(true)
throw new Foo();
return 42;
基本上编译器必须停在某处。特别是Scala编译器,已经很慢了。一旦它将true
视为始终通过条件,您可能会问:1 == 1
,2 * 21 == 42
甚至是x == 7
,其中x
是val
很难绘制一条线,因此编译器只是假设每个if
都可以有两个分支。 IDE或代码验证工具负责发现这些不可能或可能不正确的表达。
答案 1 :(得分:4)
我认为你不希望Int
- 推断的类型不应该依赖于优化,而应该依赖于开发人员编写的文本。否则,很难预测你会得到什么 - 被授予,而不是在这种情况下,但它显然比大多数人更明显。
答案 2 :(得分:2)
因为类型检查器不对程序的执行做出任何假设。它不会尝试预测if语句的哪个分支将执行。在一般情况下,这是不可判定的,而且这种特殊情况在实践中不会经常发生,使任何此类预测都值得。
执行此类预测还会使输入规则的逻辑变得复杂。如果if语句的类型是Int,而其中一个分支的类型不是Int的子类型,那肯定会与人们的期望相矛盾 - 即使分支永远不会被执行。在某种程度上,就像类型检查器不会抱怨它知道不会执行的分支中的类型错误一样 - 没有人会想要它。
答案 3 :(得分:0)
这让我思考,因为你可以移动到定义true
的地方。在某些时候,编译器需要遵循很多路径来提出它的最佳猜测。
这总是如此
if (true) 1 else false
也是如此,但处于更高的水平
val presetBoolean = true
if (presetBoolean) 1 else false
这样,但是通过评估表达式
val presetBoolean = (1 == 1)
if (presetBoolean) 1 else false
这也是常量,但在这种情况下,它将引用传递给另一个对象(并且是我程序中唯一的实例
case object CallWithPreset {
def apply(presetBoolean:Boolean) {
if(presetBoolean) 1 else false
}
}
CallWithPreset(true)
每个推理都有编译时间形式的开销。因此,虽然我认为在琐碎的情况下它可能很容易,但在其他情况下可能不会。但是,如果您允许某些情况而不是所有情况,则会导致每个情况可能具有不同的推断并且可能会造成混淆。
例如,如果有效:
val myType:Int = if(true) 1 else false
但这给出了编译错误:
val presetBoolean = true
val myType:Int = if (presetBoolean) 1 else false