Соответствие шаблону Scala строковому имени переменной - PullRequest
14 голосов
/ 18 декабря 2010

Я обнаружил, что при использовании сопоставления с образцом с альтернативами (для строк) Scala принимает переменные, начинающиеся с верхнего регистра (в приведенном ниже примере MyValue1 и MyValue2), но не те, которые начинаются с нижнего регистра (myValue1myValue2).Это ошибка или особенность 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, подразумевая, что первый всегда совпадает.

Ответы [ 4 ]

37 голосов
/ 18 декабря 2010

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

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

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")
}
8 голосов
/ 19 декабря 2010

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

Вы привели пример того, что это не имеет смысла:

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 константы - это верблюжьи буквы, начинающиеся с заглавной буквы, а методы, а также значения и переменные (которые на самом деле тоже методы) начинаются с верблюда, начиная со строчных букв. Таким образом, константы естественно обрабатываются как литералы, в то время как другие рассматриваются как присваиваемые идентификаторы (которые могут скрывать идентификаторы, определенные во внешнем контексте).

5 голосов
/ 18 декабря 2010

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

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

scala> x match {
 | case MyValue1 | MyValue2 => println ("first match")
 | case myValue1 => println (myValue1)
 | }
test
2 голосов
/ 19 декабря 2010

Если это поможет, я только что опубликовал статью на эту тему около недели @ http://asoftsea.tumblr.com/post/2102257493/magic-match-sticks-and-burnt-fingers

...