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
Ответ 4
Если это помогает, я просто разместил статью по этой теме неделю или около того @http://asoftsea.tumblr.com/post/2102257493/magic-match-sticks-and-burnt-fingers