Странное scala поведение кортежа - PullRequest
3 голосов
/ 18 апреля 2020

Я заметил такое поведение в Scala

val list = List[(Int, Int)]()
val set = HashSet[(Int, Int)]()

scala> list :+ (1, 2)
res30: List[(Int, Int)] = List((1,2))

scala> list :+ (1 -> 2)
res31: List[(Int, Int)] = List((1,2))

scala> list :+ 1 -> 2
res32: List[(Int, Int)] = List((1,2))

//Work
// But the same for set not work
set += (1, 2)
<console>:14: error: type mismatch;
 found   : Int(2)
 required: (Int, Int)
       set += (1, 2)

//Ok may be += in set mean add all that mean this should work
set += ((1, 2))
set += ((1, 2), (3,4))
// Worked

// But why this one work
set += 1 -> 2
set += (1 -> 2)
set += ((1 -> 2))

Теперь я запутался, не могли бы вы объяснить, почему кортеж не является кортежем?

scala> (4->5).getClass
res28: Class[_ <: (Int, Int)] = class scala.Tuple2

scala> (4,7).getClass
res29: Class[_ <: (Int, Int)] = class scala.Tuple2$mcII$sp

Ответы [ 2 ]

5 голосов
/ 18 апреля 2020

Этап синтаксического анализа -Xprint:parser дает

set.$plus$eq(1, 2)

, который, кажется, разрешает в

def += (elem1: A, elem2: A, elems: A*)

, который является методом, который принимает несколько аргументов, так что компилятор, вероятно, думает elem1 = 1 или elem2 = 2 вместо того, чтобы рассматривать (1,2) как кортеж.

отсутствующий фактор указывает на SLS 6.12.3 Операции с инфиксами в качестве объяснения

Правый операнд левоассоциативного оператора может состоять из нескольких аргументов, заключенных в скобки, например, ?; op; (?1,…, ??). Это выражение затем интерпретируется как op.op (?1,…, ??).

Теперь оператор += является левоассоциативным, поскольку он не заканчивается на :, а правый ручной операнд += состоит из нескольких аргументов, заключенных в скобки (1,2). Поэтому, по замыслу, компилятор не обрабатывает (1,2) как Tuple2.

5 голосов
/ 18 апреля 2020

Я думаю, что разница в том, что HashSet[T] определяет две перегрузки для +=, одна из которых принимает один T, а другая - несколько (как список T* параметров). Это унаследовано от Growable[T] и показано здесь .

List[T].:+ может занимать только один T с правой стороны, поэтому Компилятор выясняет, что он смотрит на кортеж, а не на то, что должно быть превращено в список параметров.

Если вы выполните set += ((1, 2)), то он скомпилируется. Кроме того, val tuple = (1,2); set += x тоже работает.

См. Ответ Марио Галича о том, почему в случае HashSet[T].+= компилятор выбирает перегрузку, которая не может печатать, над той, которая может.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...