#scala #pattern-matching
#scala #сопоставление с шаблоном
Вопрос:
def test1(a: Any) = a match {
case x: AnyRef => "AnyRef"
case _ => "None of the above"
}
def test2(a: Any) = a match {
case x: Double if x > 2 => "Double > 2"
case x: AnyRef => "AnyRef"
case _ => "None of the above"
}
Пожалуйста, кто-нибудь может объяснить, почему в приведенном ниже первом случае 1.0
совпадение включено AnyRef
, а во втором — нет. (Scala 2.9.0-1)
scala> test1(1.0)
res28: java.lang.String = AnyRef
scala> test2(1.0)
res29: java.lang.String = None of the above
редактировать — Обновление Scala 2.10 от января 2013: новый механизм сопоставления шаблонов исправляет это поведение (или, по крайней мере, делает его согласованным), и метод test2
теперь возвращает «AnyRef» как для test1
.
Комментарии:
1. при компиляции генерируется if(экземпляр Double) { if(a > 2) { возвращает «Double > 2»} else { возвращает «Ничего из вышеперечисленного» } } else { if (экземпляр объекта) { возвращает «AnyRef»} else {возвращает «Ничего из вышеперечисленного»}} . Итак, если кто-нибудь не найдет что-нибудь в спецификации scala, я думаю, что это ошибка компилятора scala
2.
1.0
является a,Double
который является подтипомAny
, но не ofAnyRef
в отличие отjava.lang.Double
. Поэтому я даже удивляюсь, почему1.0
совпаденияAnyRef
вtest1
.3. Я удалил свой ответ. Это не ошибка — я не заметил, чтобы вы сопоставляли с
AnyRef
. Рекс Керр прав.4. @PeterSchmitz: согласно спецификации, вы правы.
Ответ №1:
Это потому, что Any
на самом деле это просто Object
. Поскольку Double
существует удобная фикция — на самом деле это java.lang.Double
то, что автоматически устанавливается для вас в инструкции match. К сожалению, у Scala нет способа определить, находит ли она java.lang.Double
, должно ли это интерпретироваться как Double
или как a java.lang.Double
— в последнем случае AnyRef
это должно быть перехвачено. Так и есть. Но если вы специально запрашиваете a Double
, он знает, что он должен быть распакован, и тогда AnyRef
регистр проверять не нужно. (И, на самом деле, если вы предполагали, что это будет java.lang.Double
, это тоже будет распаковано — он не сможет определить разницу.)
Является ли это идеальным поведением, спорно, но оно логично.
Комментарии:
1. Спасибо, теперь я понимаю, почему
1.0
это сопоставляется вtest1
.2. @RexKerr Я не уверен, что все еще верю в это. «в последнем случае AnyRef должен это перехватить». за исключением того, что этого не происходит, поскольку «Ничего из вышеперечисленного» не напечатано. Я также предполагаю, что результат сопоставления должен быть равен составлению частичных функций…
val x:PartialFunction[Any, String] = {case x:Double if x > 2 => "Double > 2"} val y:PartialFunction[Any, String] = {case x:AnyRef => "AnyRef"} val z:PartialFunction[Any, String] = {case _ => "None of the Above"} println(test2(1.0)) // => None of the Above val chain = x orElse y orElse z println(chain(1.0)) // => AnyRef
3.@DanielHinojosa — Как я уже сказал, я не уверен, что это идеально:
AnyRef
должно перехватывать это , если вы не укажете, что хотитеDouble
. Можно утверждать, что защита наDouble
должна указывать, что вы хотите, чтобы только теDouble
, которые будут рассматриваться как не-AnyRef
, а остальные должны быть перехваченыAnyRef
как обычно.4. Описано ли это поведение в спецификации Scala? Мне действительно интересно, как нынешнее поведение может быть формализовано в целом.
5. @RexKerr: Ну, это не будет распространяться ни на
AnyVal
дочерние элементы, ни на перестановки разных случаев. В любом случае, я просмотрел спецификацию, и ни в разделах 12.2, ни в разделах 8.1-8.2 нет намека на какую-либо подобную проблему, поэтому первый фрагмент кода не согласуется со спецификацией. Но я боюсь, что настанет день, когда сопоставление сAnyRef
будет работать и совпадения сAnyVal
будут отфильтровываться, учитывая стоимость производительности. Я думаю, что совпадения сAnyRef
должны вызывать предупреждение или ошибку, предлагая сопоставить сAny
, тем более чтоAnyVal
это уже запрещено.