用 Map#getOrElse 输入奇怪的东西 [英] Type weirdness with Map#getOrElse
问题描述
考虑
scala> val m = Map('a -> 3, 'b -> 4)
m: scala.collection.immutable.Map[Symbol,Int] = Map('a -> 3, 'b -> 4)
scala> val d: Double = m.getOrElse('c, 0)
<console>:8: error: type mismatch;
found : AnyVal
required: Double
val d: Double = m.getOrElse('c, 0)
^
scala> m.getOrElse('c, 0)
res0: Int = 0
scala> m.getOrElse('a, 0)
res1: Int = 3
为什么 Scala 认为 getOrElse
调用返回 AnyVal
,即使它显然返回一个 Int
?
Why is it that Scala thinks that the getOrElse
call returns AnyVal
even tho it obviously returns an Int
?
此外,即使这样也会失败并出现相同的错误:
Furthermore, even this fails with the same error:
scala> val x: Double = m.getOrElse('a, 0): Double
<console>:8: error: type mismatch;
found : AnyVal
required: Double
val x: Double = m.getOrElse('a, 0): Double
然而这有效:
scala> val x: Double = m.getOrElse('a, 0): Int
x: Double = 3.0
这发生在 2.11.x 上;我没有在 2.10.x 上试过.
This happens on 2.11.x; I have no tried it on 2.10.x.
推荐答案
我正在努力更好地阅读 -Ytyper-debug
输出.
I'm trying to get better at reading -Ytyper-debug
output.
在预期类型Double
下,0
的类型取为Double
,0.0
.这是因为人们讨厌不断扩大的转化.
With the expected type Double
, the type of 0
is taken as Double
, 0.0
. That's because of the widening conversions people hate.
这是在求解 B1
之前.B1
被当作 AnyVal
因为那是 A
/Int
和 Double
的结合>.
This is before solving for B1
. B1
is taken as AnyVal
because that is the lub of A
/Int
and Double
.
| |-- Double TYPEmode (site: value d in $iw)
| | \-> Double
| |-- m.getOrElse(scala.Symbol("c"), 0) : pt=Double BYVALmode-EXPRmode (site: value d in $iw)
| | |-- m.getOrElse BYVALmode-EXPRmode-FUNmode-POLYmode (silent: value d in $iw)
| | | |-- m EXPRmode-POLYmode-QUALmode (silent: value d in $iw)
| | | | \-> m.type (with underlying type scala.collection.immutable.Map[Symbol,Int])
| | | [adapt] [B1 >: B](key: A, default: => B1)B1 adapted to [B1 >: B](key: A, default: => B1)B1
| | | \-> (key: Symbol, default: => B1)B1
| | |-- scala.Symbol("c") : pt=Symbol BYVALmode-EXPRmode-POLYmode (site: value d in $iw)
| | | |-- scala.Symbol BYVALmode-EXPRmode-FUNmode-POLYmode (silent: value d in $iw)
| | | | |-- scala.Symbol.apply BYVALmode-EXPRmode-FUNmode-POLYmode (silent: value d in $iw)
| | | | | \-> (name: String)Symbol
| | | | [adapt] Symbol.type adapted to (name: String)Symbol
| | | | \-> (name: String)Symbol
| | | |-- "c" : pt=String BYVALmode-EXPRmode (silent: value d in $iw)
| | | | \-> String("c")
| | | \-> Symbol
| | |-- 0 : pt=Double EXPRmode-POLYmode (site: value d in $iw)
| | | \-> Double(0.0)
| | solving for (B1: ?B1)
<console>:8: error: type mismatch;
found : AnyVal
required: Double
val d: Double = m.getOrElse('c, 0)
^
| | \-> <error>
另外,-xprint:typer
显示
m.getOrElse[AnyVal](scala.Symbol.apply("c"), 0.0);
规范解释了(情况 3 方法)使用参数的预期类型对 args 进行类型检查,这就是为什么您在那里转换为 Double
,而不是让方法返回 Int
在赋值中扩展为 Double
.
The spec explains (case 3 methods) that the args are typechecked with the expected type of the param, which is why you get the conversion to Double
there, instead of having the method return an Int
that is widened to Double
in the assignment.
这篇关于用 Map#getOrElse 输入奇怪的东西的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!