包含映射的选项的Scala隐式

包含映射的选项的Scala隐式,scala,implicit,Scala,Implicit,我试图写下以下内容: implicit class ExtractOrElse[K, V](o: Option[Map[K, V]]) { def extractOrElse(key: K)(f: => V): V = { if (o.isDefined) o.get(key) else f } } 我想这样使用: normalizationContexts.extractOrElse(shardId)(defaultNormalizationContext) 为了避免更笨拙的语法

我试图写下以下内容:

implicit class ExtractOrElse[K, V](o: Option[Map[K, V]]) {
  def extractOrElse(key: K)(f: => V): V = { if (o.isDefined) o.get(key) else f }
}
我想这样使用:

normalizationContexts.extractOrElse(shardId)(defaultNormalizationContext)
为了避免更笨拙的语法(
normalizationcontext
是一个
选项[Map[String,NormzalitionContext]]

另外,让我补充一下,只有一个默认值是有意的:如果
选项
为空
,则将使用该默认值,但如果
选项
已定义
,则
映射的行为不会更改,如果找不到键,它将抛出一个异常-因此在这种情况下不会使用默认值,这都是故意的

但是,我在单元测试中传入
None
时出错:

assertEquals(None.extractOrElse('a')(0), 0)
结果:

Error:(165, 37) type mismatch;
 found   : Char('a')
 required: K
  assertEquals(None.extractOrElse('a')(0), 0)
我意识到
None
不是参数化的,因为它被定义为:

case object None extends Option[Nothing] {
  def isEmpty = true
  def get = throw new NoSuchElementException("None.get")

什么是最好的方式使这项工作

类型系统没有关于类型
K
V
的足够信息。如果您的
None
Some[A]
,则无法知道
A
的类型

当我创建带有显式类型的示例时,代码按预期工作:

// Like this
val e = new ExtractOrElse(Option.empty[Map[Char, Int]])
e.extractOrElse('a')(0) // Equals 0

// Or like this
val e = new ExtractOrElse[Char, Int](None)
println(e.extractOrElse('a')(0))

// Or like this
val m: Option[Map[Char, Int]] = None
val e = new ExtractOrElse(m)
println(e.extractOrElse('a')(0))

不要使用
None.extractOrElse(…)
,请尝试使用
Option.empty[Map[Char,Int]].extractOrElse(…)

如果您总是对测试用例使用相同的类型,那么还可以在specs类中创建一个类型别名,以减少混乱:

type OpMap = Option[Map[Char, Int]]
// ...
assertEquals(Option.empty[OpMap].extractOrElse('a')(0), 0)
以防万一,您可以使用
flatMap
getOrElse
实现相同的功能,而无需编写新方法:

val n = Option.empty[Map[String, Int]]
val s = Some(Map("x" → 1, "y" → 2))

n.flatMap(_.get("x")).getOrElse(3)  // 3
s.flatMap(_.get("x")).getOrElse(3)  // 1
s.flatMap(_.get("z")).getOrElse(3)  // 3

最后两个例子可以更好地写成
println((None:Option[Map[Char,Int]])。extractOrElse('a')(0)
。这是这个问题最简单的答案。我认为三个不同的例子说明了如何提供类型信息就足够了。有趣的是,我可以在
extractOrElse
的实现中使用
flatMap.getOrElse
(我仍然喜欢更简单的语法)。它是
Option.empy[OpMap]
还是
Option.empty[Map[String,Int]
?我认为是后者……还有,它是
flatMap
还是
Map
flatMap
的签名是
flatMap[B](f:A=>Option[B]):Option[B]
@Frank:就我的例子来说,它是
[Map[String,Int]
,但对你来说它是
[OpMap]
@Frank:如果你使用
map
你得到嵌套的
选项
s,那么你需要在两个层次上
getOrElse
:m.map(code.get(“x”).getOrElse(3)).getOrElse(3)
。通过使用
flatMap
你可以展平嵌套的
选项
s,只能够展平
getOrElse