У меня есть класс случая
case class ~[a,b](_1:a, _2:b)
Когда я хочу сделать соответствие pattetn
new ~("a", 25) match{
case "a" ~ 25 =>
}
Я могу использовать его этот путь потому что "a" ~ 25
и ~("a", 25)
эквивалентны. Но если я хочу соответствовать new ~("a", new ~("b", 25))
{case "a" ~ "b" ~ 25 => }
проблемы начинаются. Я понимаю, что это операторы не эквивалентно. Так, как new ~("a", new ~("b", 25))
может быть представлен? Какой правила?
Это работает:
new ~("a", new ~("b", 25)) match {
case "a" ~ ("b" ~ 25) =>
}
Итак, вы должны поставить круглые скобки так же, как они стоят в начальном предложении. Иначе тильда является лево-ассоциативной, поэтому тип шаблона будет другим, и он не скомпилируется.
case "a" ~ "b" ~ 25
то же самое, что и
case ("a" ~ "b") ~ 25
что в вашем случае было бы неправильно.
Приложение
Вы можете получить правую ассоциативность, используя двоеточие в качестве последнего символа в имени класса/метода. Следующее компилируется и работает без круглых скобок (и вы можете опустить new
, так как компилятор больше не будет путаться в $tilde$colon
):
case class ~:[a,b](_1:a, _2:b)
~:("a", ~:("b", 25)) match {
case "a" ~: "b" ~: 25 =>
}
Ответы
1) Без ключевого слова new
класс case ~
затеняется unary_~
, который дает побитовое отрицание аргумента. Выражение типа ~ 2
внутренне оценивается как unary_~(2)
и то же самое относится к случаю ~ ("a", 1)
- однако если вы не определите unary_~
для этого кортежа, это приведет к ошибке. С помощью ключевого слова new
вы указываете компилятору явно искать класс с таким именем, чтобы он не запутался.
(Технически, вы можете обойти это, используя $tilde("a", 1)
, которое является внутренним именем вашего класса case ~
, но поскольку это деталь компилятора, вам, вероятно, не следует полагаться на нее.)
2 и 3) Ссылка на право-ассоциативность содержится в Scala Language Specification. Раздел 'Infix Operations'
Ассоциативность оператора определяется последним символом оператора. Операторы, заканчивающиеся двоеточием ':', являются право-ассоциативными. Все остальные операторы являются лево-ассоциативными.
Кстати, правая ассоциативность - это трюк, позволяющий создавать списки с Nil
. (Nil
- это пустой List
, для которого определен право-ассоциативный оператор конкатенации ::
)
val l: List[Int] = 1 :: 2 :: 3 :: Nil
который оценивается следующим образом
val l: List[Int] = (1 :: (2 :: (3 :: Nil)))
или, точнее, поскольку 3 :: Nil
≡ Nil. ::(3)
, так как
val l: List[Int] = ( ( Nil.::(3) ).::(2) ).::(1)