包含映射的选项的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
。