Scala соответствие шаблону с наименьшим именем переменной

Я обнаружил, что при использовании сопоставления шаблонов с альтернативами (для строк) Scala принимает переменные, начиная с верхнего регистра (в примере ниже, MyValue1 и MyValue2), но не те, которые начинаются с нижнего регистра (MyValue1, MyValue2). Является ли это ошибкой или функцией Scala? Я получаю это в версии 2.8. Если это особенность, может ли кто-нибудь объяснить обоснование этого? Это код, который я использовал:

val myValue1 = "hello"
val myValue2 = "world"
val MyValue1 = "hello"
val MyValue2 = "world"

var x:String = "test"

x match {
  case MyValue1 | MyValue2 => println ("first match")
  case myValue1 | myValue2 => println ("second match")
}

При запуске я получаю следующее:

scala> val myValue1 = "hello"
myValue1: java.lang.String = hello

scala> val myValue2 = "world"
myValue2: java.lang.String = world

scala> val MyValue1 = "hello"
MyValue1: java.lang.String = hello

scala> val MyValue2 = "world"
MyValue2: java.lang.String = world

scala> var x:String = "test"
x: String = test

scala> x match {
 |   case MyValue1 | MyValue2 => println ("first match")
 |   case myValue1 | myValue2 => println ("second match")
 | }
<console>:11: error: illegal variable in pattern alternative
     case myValue1 | myValue2 => println ("second match")
          ^
<console>:11: error: illegal variable in pattern alternative
     case myValue1 | myValue2 => println ("second match")
                     ^

ИЗМЕНИТЬ

Итак, это действительно функция, а не ошибка... Может ли кто-нибудь представить пример, когда это может быть полезно?

Когда я использую:

x match {
   case myValue1 => println ("match")
   case _ => 
}

Я получаю предупреждение unreachable code в последнем случае, подразумевая, что первое всегда совпадает.

Ответы

Ответ 1

Это не относится к шаблонам с альтернативами, и это не ошибка. Идентификатор, начинающийся с строчной буквы в шаблоне, представляет новую переменную, которая будет привязана, если шаблон соответствует.

Итак, ваш пример эквивалентен написанию:

x match {
   case MyValue1 | MyValue2 => println ("first match")
   case y | z => println ("second match")
}

Вы можете обойти это, используя обратные ссылки:

x match {
   case MyValue1 | MyValue2 => println ("first match")
   case `myValue1` | `myValue2` => println ("second match")
}

Ответ 2

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

Вы привели пример, не имеющий смысла:

x match {
   case myValue1 => println ("match")
   case _ => 
}

Но смысл легко увидеть, если мы немного изменим:

x match {
   case MyValue1 => println("match")
   case MyValue2 => println("match")
   case other    => println("no match: "+other)
}

Конечно, можно использовать x вместо other выше, но вот некоторые примеры, когда это было бы неудобно:

(pattern findFirstIn text) {
    // "group1" and "group2" have been extracted, so were not available before
    case pattern(group1, group2) =>

    // "other" is the result of an expression, which you'd have to repeat otherwise
    case other =>
}

getAny match {
    // Here "s" is a already a string, whereas "getAny" would have to be typecast
    case s: String =>

    // Here "i" is a already an int, whereas "getAny" would have to be typecase
    case i: Int =>
}

Таким образом, существует множество причин, почему удобно для сопоставления шаблонов назначать сопоставленное значение идентификатору.

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

Ответ 3

Что здесь происходит, так это то, что myValue1 и myValue2 рассматриваются как переменные идентификаторы (т.е. определение новых переменных, привязанных к сопоставляемому значению), тогда как MyValue1 и MyValue2 рассматриваются как стабильные идентификаторы, которые ссылаются на значения, объявленные ранее, В случае соответствия шаблона идентификаторы переменных должны начинаться с буквы нижнего регистра, поэтому почему первый случай ведет себя интуитивно. Подробные сведения см. В разделе 8.1 спецификации языка Scala (http://www.scala-lang.org/docu/files/ScalaReference.pdf).

Немного изменив ваш пример, вы увидите идентификатор переменной:

scala> x match {
 | case MyValue1 | MyValue2 => println ("first match")
 | case myValue1 => println (myValue1)
 | }
test