用 Map#getOrElse 输入奇怪的东西 [英] Type weirdness with Map#getOrElse

查看:49
本文介绍了用 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的类型取为Double0.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/IntDouble 的结合>.

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屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆