Это работает:
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 class ~
затеняется unary_~
, что дает побитовое отрицание аргумента. Выражение типа ~ 2
внутренне оценивается как unary_~(2)
, и то же самое относится к случаю ~ ("a", 1)
- однако, если вы не определите unary_~
для этого кортежа, это выдаст ошибку. С ключевым словом new
вы советуете компилятору явно искать класс с таким именем, чтобы он не запутался.
(Технически, вы можете обойти это, используя $tilde("a", 1)
, которое является внутренним именем вашего case class ~
, но, поскольку это деталь компилятора, вам, вероятно, не следует полагаться на него.)
2 & 3) Правоассоциативности указано в Спецификации языка Scala . Раздел «Операции с инфиксами»
Ассоциативность оператора определяется последним символом оператора. Операторы, оканчивающиеся на двоеточие ‘:’, ассоциированы справа. Все остальные операторы левоассоциативны.
Кстати, правоассоциативность - это уловка, которая позволяет создавать списки с 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)