scala Map.getOrElse - 如何提供默认函数

use*_*956 7 scala

奇...

    val h = new HashMap[Long, Int]()

    def mydefault0():Int = 101
    println( h.getOrElse(99, default=mydefault0 _ ) )  // Prints <function0>

    def mydefault1(key:Long):Int = 102
    println( h.getOrElse(98, default=mydefault1 _ ) )  // Prints <function1>
Run Code Online (Sandbox Code Playgroud)

文档说,默认类型必须为:=>乙

如果我理解正确,在这种情况下返回Int的无参数函数.

  1. 为什么采用mydefault1编译的示例,因为它需要一个参数,所以符合规范?

  2. 为什么返回函数,而不是调用函数来产生默认值?显然,类型安全已被破坏,因为getOrElse必须返回Int,而不是函数.(如果我误解了文档并错误地提供了需要Int值的函数,为什么编译器让我提供一个函数,而不是Int?).

编辑

很明显:

  • 扩展HashMap并覆盖默认值,或
  • 使用HashMap.withDefault

还让一个函数用于指定默认值.我想要的是能够使用在执行查找时提供的函数覆盖默认值(即函数可能在Map的生命周期中发生变化)

这可能吗?

0__*_*0__ 16

定义getOrElse:

getOrElse[B1 >: B](key: A, default: => B1): B1
Run Code Online (Sandbox Code Playgroud)

default参数不是一个函数 - 这将是() => B1一个懒惰访问的类型值B1.这个无参数的"函数" => B1有时也被称为thunk.使用它的正确方法如下:

import collection.mutable

val h = new mutable.HashMap[Long, Int]()

def mydefault0(): Int = 101

println(h.getOrElse(99, default = mydefault0()))
Run Code Online (Sandbox Code Playgroud)

那你看到的是mydefault0 _什么?显然,返回的值的类型B1必须是映射的值类型Int和默认值的类型的常见超类型.默认值的类型是Function0.如果您分配结果,您会看到超类型是Any:

val x = h.getOrElse(99, default = mydefault0 _ )  // x: Any = <function0>
Run Code Online (Sandbox Code Playgroud)

所以错误就是假设你必须传入一个函数,而实际上你正在陈述一个懒惰评估的表达式.呼叫mydefault0()需要缺省值的时候才会被调用.形式上,参数被定义为按名称调用参数.


编辑:关于你的评论.呼叫按名字的意思是,你做的每一次得到一个新的阵列.

val m = Map("foo" -> Array(1, 2, 3))

def myDefault = {
  println("called-default")
  Array(4, 5, 6)
}

val a1 = m.getOrElse("foo", myDefault)  // myDefault not called
val a2 = m.getOrElse("bar", myDefault)  // myDefault called
val a3 = m.getOrElse("baz", myDefault)  // myDefault called
a2 == a3  // false!!
Run Code Online (Sandbox Code Playgroud)

  • 正确理解什么是按名称参数以及它们的行为方式(以及它们为什么*不*“懒惰”)非常重要。关于按名称参数,最重要的一点是,*调用* 方法决定了实际参数表达式的计算次数,可能是 0、1 * 或更多 * 次。惰性参数仅评估 0 或 1 次。 (2认同)