Scala - как сопоставить шаблон при объединении двух неявных преобразований? - PullRequest
0 голосов
/ 25 февраля 2019

Я написал метод для анализа данных метрик и сначала столкнулся с проблемой с типом транзакцииMap, который является java.util.Map.И я решил это с помощью JavaConverters.

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

Но после этого я получил ошибку при сопоставлении с образцом значений true и false: pattern type is incompatible with expected type, found: Boolean, required: java.lang.Boolean

Насколько я понимаю, Scala не связывает два неявных преобразования.Есть ли способ исправить это с помощью JavaConverters?

Ответы [ 2 ]

0 голосов
/ 25 февраля 2019

Другой ответ предоставляет разумный способ решения этой проблемы, но не показывает, почему вы сталкиваетесь с этим или как работает предлагаемый подход.

Стандартная библиотека Scala обеспечивает неявное преобразованиеот java.lang.Boolean до scala.Boolean, который вы можете увидеть в действии, используя reify в REPL для десугарации некоторого кода, который использует логическое значение Java в контексте, где ожидается логическое значение 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)

Проблема в том, что простой попытки сопоставить значение java.lang.Boolean с true или false недостаточно для запуска преобразования.Вы можете проверить это, определив свои собственные типы, где вы можете быть уверены, что точно знаете, какие конверсии находятся в игре:

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 }
                             ^

Это решение для языкового дизайна.Вероятно, было бы возможно применить неявные преобразования в этих сценариях, но, вероятно, есть и веская причина, по которой они этого не делают (из головы в голову, я не знаком с какими-либо соответствующими обсуждениями или проблемами, но это не так).это означает, что они не существуют).

Причина, по которой решение Энди работает, заключается в том, что 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
}

… но, на мой взгляд, сопоставление с шаблоном на Boolean немного сложнее, чем использование условного выражения.

0 голосов
/ 25 февраля 2019

Используйте if / else вместо оператора match для логической проверки:

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

Я подозреваю, что в операторе if можно привести java.lang.Boolean (который, я полагаю, x здесь),на Boolean через import scala.collection.JavaConverters._ ... но оператор сопоставления не делает то же самое принуждение, но должен был бы быть сделан явно (или совпадать со значениями java.lang.Boolean).

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...