Понимание вызова инфиксного метода и оператора cons (: :) в Scala - PullRequest
18 голосов
/ 05 июля 2010

Я довольно новичок в языке программирования Scala и пробовал что-то застрявшее в моей голове, когда я читал лекционные заметки в здесь .

Мне кажется, я не мог понять, как работает оператор cons, вот несколько вещей, которые я пробовал:

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

scala> val gen = new java.util.Random
gen: java.util.Random = java.util.Random@1b27332

scala> gen nextInt 3 :: Nil
<console>:7: error: type mismatch;
 found   : List[Int]
 required: Int
       gen nextInt 3 :: Nil
                     ^

Но он попытался передать List (3) следующему методу. Когда я использовал паратезы, проблем не было

scala> (gen nextInt 3) :: Nil
res69: List[Int] = List(1)

Мне было любопытно узнать порядок выполнения, поэтому я создал функцию для его проверки

scala> def pr(i:Int):Int = { println(i); i }
pr: (i: Int)Int

scala> pr(1) :: pr(2) :: pr(3) :: Nil
1
2
3
res71: List[Int] = List(1, 2, 3)

Как видно из результатов, порядок выполнения такой же, как и порядок появления. Тогда я подумал, что это может быть функция 'nextInt', затем я попытался выполнить следующее:

scala> 1 + 2 :: Nil
res72: List[Int] = List(3)

Сначала выполняется сложение, а после этого выполняются минусы. Итак, вот вопрос: в чем разница между gen nextInt 3 :: Nil и 1 + 2 :: Nil?

Ответы [ 2 ]

41 голосов
/ 06 июля 2010

Здесь есть две проблемы: приоритет и фиксированность . Как упоминалось в sepp2k, этот вопрос о переполнении стека объясняет приоритет, считая, что приведенные правила недостаточно полны, и произошли очень небольшие изменения с Scala 2.7 до Scala 2.8. Различия касаются в основном операторов, оканчивающихся на =.

Что касается fixity , то почти все в Scala читается слева направо, к чему привыкли программисты. Однако в Scala операторы, оканчивающиеся на :, читаются справа налево.

Возьмем, к примеру, этот пример:

1 + 2 :: Nil

Во-первых, приоритет. Что имеет наибольшее преимущество, + или :? Согласно таблице, + имеет приоритет над :, поэтому добавление выполняется первым. Следовательно, выражение равно этому:

((1).+(2)) :: Nil

Теперь нет конфликта приоритетов, но, поскольку :: оканчивается на :, он имеет другую фиксированность. Читается справа налево, поэтому:

Nil.::((1).+(2))

С другой стороны, в этом:

gen nextInt 3 :: Nil

Оператор :: имеет приоритет над nextInt, потому что : имеет приоритет над всеми буквами. Поэтому, вспоминая свою стойкость, она становится:

gen nextInt Nil.::(3)

Который затем становится

gen.nextInt(Nil.::(3))

В этот момент ошибка очевидна.

PS: я пишу (1).+(2) вместо 1.+(2), потому что на момент написания этой статьи 1. интерпретировалось как двойное число, делая 1.+(2) инфиксным выражением с добавлением двойного 1,0 к 2. Этот синтаксис устарел в Scala 2.10.0 и, вероятно, не будет присутствовать в Scala 2.11.

3 голосов
/ 05 июля 2010

Речь идет о приоритете, а не о порядке исполнения.+ имеет более высокий приоритет, чем ::, поэтому a + b :: c анализируется как (a + b) :: c.Однако вызовы инфиксных методов с обычными именами имеют более низкий приоритет, поэтому a foo b c анализируется как a foo (b c).

. См. в этом вопросе для списка операторов, упорядоченных по приоритету в scala.*

...