Почему оператор ++: в языке Scala такой странный?

Я использую оператор ++: для получения коллекции из двух коллекций, но результаты, которые я получаю с помощью этих двух методов, противоречивы:

scala> var r = Array(1, 2)
r: Array[Int] = Array(1, 2)
scala> r ++:= Array(3)
scala> r
res28: Array[Int] = Array(3, 1, 2)

scala> Array(1, 2) ++: Array(3)
res29: Array[Int] = Array(1, 2, 3)

Почему операторы ++: и ++:= дают разные результаты? Такая разница не появляется с оператором ++.

Я использую версию Scala 2.11.8.


person xuejianbest    schedule 16.11.2018    source источник
comment
Еще один интересный эффект ++: и ++:= заключается в том, что он берет тип коллекции результатов с правой стороны (в случае, если они не являются массивами, как здесь, stackoverflow.com/a/24338494/14955) --- для некоторого определения правой руки в присутствии ++:=.   -  person Thilo    schedule 16.11.2018


Ответы (2)


Поскольку он заканчивается двоеточием, ++: является правоассоциативным. Это означает, что Array(1, 2) ++: Array(3) эквивалентно Array(3).++:(Array(1, 2)). ++: можно рассматривать как «добавление элементов левого массива в начало правого массива».

Так как это право-ассоциативно, r ++:= Array(3) обесахаривает до r = Array(3) ++: r. Это имеет смысл, если учесть, что цель ++: предшествует. Это обескураживание справедливо для любого оператора, оканчивающегося двоеточием.

Если вы хотите добавить, вы можете использовать ++++=).

person Brian McCutchon    schedule 16.11.2018
comment
@Thilo +:, :: и ::: приходят на ум. Опять же, это все, что заканчивается двоеточием. - person Brian McCutchon; 16.11.2018
comment
@Thilo: в Scala нет такого понятия, как оператор. Любой метод можно вызвать без точки, например: a foo(bar, baz), а когда вы передаете только один аргумент, вы можете опустить круглую скобку, например: a foo bar. Вот и все. Это обычный вызов метода, а ++ — это обычное имя метода, например foo. Однако есть два исключения, которые означают, что Scala на самом деле действительно имеет полуоператоры. 1) Приоритет определяется первым символом имени метода. 2) Методы, оканчивающиеся на :, являются правоассоциативными при вызове с операторным синтаксисом. - person Jörg W Mittag; 16.11.2018
comment
Примечание: это также относится к конструкторам типов. Итак, если у вас class Foo[A, B] {}, то вы, конечно, можете сказать def foo: Foo[Int, String], но вы также можете сказать def foo: Int Foo String, а если у вас class Foo_:[A, B], то Foo_:[Int, String] это то же самое, что и String Foo_: Int. - person Jörg W Mittag; 16.11.2018
comment
@JörgWMittag Немного о конструкторах типов дико. Я знаю, что Скалаз использует его для красивого Либо (def foo: String \/ Int). Есть ли примеры того, как кто-то занимается правоассоциативным типом? - person Thilo; 16.11.2018
comment
@Thilo: Вы этого не осознаете, но вы, вероятно, уже видели это, хотя на самом деле это не доступно пользователю: :: - это метод List, объект, а также класс. Но обычно вы имеете дело с List, а не с ::. - person Jörg W Mittag; 16.11.2018
comment
Ах, извините. Виноват. :: является унарным, а не бинарным. Но, наверное, кто-то так делает. - person Jörg W Mittag; 16.11.2018
comment
@Thilo Shapeless имеет конструктор бинарного типа ::. Поскольку это правоассоциативно, Int :: String :: HNil эквивалентно ::[Int, ::[String, HNil]]. - person Brian McCutchon; 16.11.2018
comment
@JörgWMittag Конструкторы типов могут быть правоассоциативными (например, shapeless.::), но в этом случае они не меняют порядок своих аргументов (к счастью). - person Brian McCutchon; 16.11.2018

Здесь двоеточие (:) означает, что функция имеет правильную ассоциативность.

так, например, coll1 ++: coll2 похож на (coll2).++:(coll1)

Что обычно означает, что элементы левой коллекции добавляются к правой коллекции

Случай 1:

Array(1,2) ++: Array(3)
Array(3).++:Array(1,2) 
Elements of the left array is prepended to the right array 
so the result would be Array(3,1,2)

Случай 2:

 r = Array(1,2)
 r ++:= Array(3) //This could also be written as the line of code below
 r = Array(3) ++: r
   = r. ++: Array(3)
   = Array(1,2). ++: Array(3) //Elements of the left array is prepended to the right array 
 so their result would be Array(1,2,3)

Надеюсь, это решит вопрос. Спасибо :)

person prasanna kumar    schedule 16.11.2018
comment
++: - это метод, а не функция. - person Brian McCutchon; 16.11.2018