Scala - 链接两个隐式转换时如何模式匹配?

sam*_*mba 4 java collections scala pattern-matching

我编写了一个解析Metrics数据的方法,并且首先遇到了transactionMap类型的问题java.util.Map.我用JavaConverters解决了它.

def parseMetrics(metric: Metric) = {
    import scala.collection.JavaConverters._
    metric.transactionMap.asScala.values.map {
      case false => "N" 
      case true => "Y"
    }.toList
Run Code Online (Sandbox Code Playgroud)

但之后我在模式匹配true和false值时出错: pattern type is incompatible with expected type, found: Boolean, required: java.lang.Boolean

据我所知,Scala没有链接两个隐式转换.有没有办法使用JavaConverters修复它?

Tra*_*own 6

另一个答案提供了解决此问题的合理方法,但没有说明您遇到它的原因或它提出的方法是如何工作的.

斯卡拉标准库不提供从隐式转换java.lang.Booleanscala.Boolean,您可以通过使用动作看reify在REPL到desugar使用在上下文Java boolean值,其中Scala的布尔预计一些代码:

scala> val x: java.lang.Boolean = true
x: Boolean = true

scala> import scala.reflect.runtime.universe.reify
import scala.reflect.runtime.universe.reify

scala> reify(if (x) 1 else 0)
res0: reflect.runtime.universe.Expr[Int] =
Expr[Int](if (Predef.Boolean2boolean($read.x))
  1
else
  0)
Run Code Online (Sandbox Code Playgroud)

问题是只是尝试匹配一个java.lang.Booleantruefalse不足以触发转换.您可以通过定义自己的类型来检查这一点,您可以确定您确切知道正在进行的转换:

scala> case class Foo(i: Int); case class Bar(i: Int)
defined class Foo
defined class Bar

scala> implicit def foo2bar(foo: Foo): Bar = Bar(foo.i)
foo2bar: (foo: Foo)Bar

scala> Foo(100) match { case Bar(x) => x }
<console>:17: error: constructor cannot be instantiated to expected type;
 found   : Bar
 required: Foo
       Foo(100) match { case Bar(x) => x }
                             ^
Run Code Online (Sandbox Code Playgroud)

这是语言设计决策.可能有可能在这些场景中应用隐式转换,但也可能有一个很好的理由,它们不是(我不熟悉任何相关的讨论或问题,但这不是'意思是他们不存在).

Andy的解决方案工作的原因是,java.lang.Boolean它处于编译器期望scala.Boolean(一个条件)并愿意应用Predef.Boolean2boolean转换的位置.如果您真的想要,您可以手动执行此操作:

def parseMetrics(metric: Metric) = {
  import scala.collection.JavaConverters._
  metric.transactionMap.asScala.values.map(Predef.Boolean2boolean).map {
    case false => "N" 
    case true => "Y"
  }.toList
}
Run Code Online (Sandbox Code Playgroud)

......但至少在我看来,模式匹配Boolean比使用条件更有点笨拙.


And*_*den 5

使用if / else而不是match语句进行布尔检查:

def parseMetrics(metric: Metric) = {
    import scala.collection.JavaConverters._
    metric.transactionMap.asScala.values.map {
      x => if (x) "Y" else "N"
    }.toList
Run Code Online (Sandbox Code Playgroud)

我的怀疑是,在if语句中,java.lang.Boolean(我想x是在这里)可以Boolean通过import scala.collection.JavaConverters._... 强制执行,但是match语句没有执行相同的强制操作,而必须显式地进行(或在java.lang.Boolean值上进行匹配) 。