2010-07-05 2 views
17

Я довольно новичок в языке программирования Scala и пытался что-то прогнать, когда я следил за лекциями в here.Понимание метода вызова вызова и consix метода (: :) в Scala

Я думаю, что я не мог понять, как работает оператор минусы, вот некоторые вещи, которые я пытался:

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

scala> val gen = new java.util.Random 
gen: java.util.Random = [email protected] 

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

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

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?

ответ

39

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

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

Take, то этот пример:

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.

+0

Спасибо за ваш подробный ответ, он дал мне много подсказок о многих других вещах. Но у меня есть еще один вопрос: Как компилятор интерпретирует выражение в третьем разделе кода, которое я дал в моем первоначальном вопросе; с точки зрения скобок? потому что использование функции pr показало, что условия выполняются в порядке слева направо. – ciuncan

+1

Правильно, вызовы функций оцениваются слева направо. Это потому, что 'pr (X)' - это выражения аргументов '::', и они сначала оцениваются по порядку появления, а затем передаются значение этому методу. 'pr (1) :: pr (2) :: pr (3) :: Nil' prints 1 2 3. Но' Nil.::(pr(3)).::(pr(2)). : :(pr (1)) 'prints 3 2 1. Но оба возвращают' List (1, 2, 3) ' –

+0

@ciuncan Я не знаю. Возможно, что нотация оператора с правильной фиксацией позволяет оценить порядок оценки с помощью точечной нотации, или может быть, что компилятор оптимизирует '::' вызовы, но имеет ошибку в отношении порядка оценки. –

3

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

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

+1

Спасибо за ваше объяснение. Приоритетом было то, о чем я просто не подумал. – ciuncan