2015-03-22 1 views
1

Я немного запутался в использовании параметров «по одному имени» в Scala. Пожалуйста, помогите мне понять, что здесь происходит. Рассмотрим следующий пример использования вызова по имени параметра:Почему параметр «по имени» указывает параметр типа Int вместо() => Int

def param = {println("Param evaluates"); 40} 
    def lazyEval(x: => Int) = { 
    println("lazy"); 
    x 
    } 
    val s = lazyEval(param + 2) 
    // s = 42 

У меня есть несколько вопрос, связанный друг с другом об этом:

  1. lazyEval метод ожидает параметр типа => Int, так почему param + 2 операция является законным? Почему мы можем добавить целое число 2 к объекту с типом => Int (im мое понимание под капотом это <function0>) при вызове метода lazyEval? Как мне подсказывает IDE, функция lazyEval ожидает параметр типа Int вместо => Int (какого черта?).

  2. Почему после изменения типа обратного вызова от => Int до () => Int код не компилируется? Являются ли эти 2 типа разными? Хотя короткая версия ('=> Int') является просто синтаксическим сахаром.

  3. После некоторых игр с кодом я, наконец, смог изменить код, поэтому он будет скомпилирован с () => Int. Этот способ более интуитивно понятен для меня.

.

def param = {println("Param evaluates"); 40} 
    def lazyEval(x:() => Int) = { // changed type to '() => Int' 
    println("lazy"); 
    x() // explicitly calling function using parentheses '()' 
    }  
    val s = lazyEval(param _) // adding underscore after method name and removing `+2` 

Что разница между этой версией и первый (с обратным => Int типа)? Почему в этой версии мы не можем добавить целое число со значением 2 и функцию param (я имею в виду это lazyEval(param _ + 2))? И что означает подчёркивание после имени метода? (Я предполагаю, что это используется, чтобы передать методу себя, а не его возвращать значение)

Спасибо помощи

ответ

3

так почему пары +-операция является законной? Почему мы можем добавить целое число 2 объекта с типом => Int

Мы можем добавить 2 к param, потому что он имеет значение Int, вы добавляете Int с Int. param не является функцией => Int, это метод, поэтому param + 2является=> Int. то есть. выражение, которое оценивается до Int.

Почему после изменения типа обратного вызова из => Int в() => Intcode не компилируется? Являются ли эти 2 типа разными? Хотя короткая версия ('=> Int') является просто синтаксическим сахаром.

=> Int и () => Int не означает одно и то же. Один - это все, что оценивается Int, а другое - от Unit до Int. 2 не () => Int, но () => 2 есть. Или вы также можете сказать 2 is => Int.

Почему в этой версии мы не можем добавить целое число со значением 2 и функцию param (я имею в виду thislazyEval (param_ + 2))? И что означает подчёркивание после имени метода? (Я предполагаю, что он использовался для прохождения самого метода, а не возвращаемого значения)

param - это метод, а не функция. Подчеркивание в этом случае поднимает param в функцию. Таким образом, param _ является функцией () => Int. И именно поэтому мы не можем добавить 2 к нему, потому что вы не можете добавить 2 к функции. В основном точная причина, почему вы думаете (1) не должна работать.


В итоге:

def lazyEval(x: => Int) представляет собой метод с параметром x, который может быть все, что имеет значение Int. Это может быть любой метод, который возвращает Int, конкретное значение Int, или какой-либо блок кода, который решает Int и т.д.

lazyEval(x:() => Int) представляет собой метод с параметром x, который может только быть функцией, которая возвращает без параметров Int. Это может означать, что метод param поднят до функции или что-то странное, как () => 2. Но это должно быть быть функцией. Поэтому просто передать значение, например 2, работать не может.

+0

Я не знаю, почему вы сказали бы, что '=> Int' не является типом или просто синтаксисом. –

+0

Вы правы. Это. –

+0

@ som-snytt Я проснулся в 4:30 после того, как я мечтал написать этот ответ, и отчаянно проверил его со своего телефона, чтобы найти ваш недавно сделанный комментарий. Естественно, я удалился на свой рабочий компьютер с моего телефона, чтобы использовать REPL, и проверить его, так как я не мог вернуться спать, не зная. Теперь, когда я в более ясном состоянии, я исправил свой ответ, чтобы не сказать такие неправильные вещи о '=> Int'. –

2

В @mz указала, value: => T можно рассматривать как синтаксиса для создания метода, который обертывает данное выражение :

object Magician { 
    def magic(param: => Int) = param 
} 

object App { 
    val result: Int = Magician.magic(3 + 3) 
} 

сдвиги (примерно) к:

object App { 
    private[this] def magic$param$1: Int = 3 + 3 
    val result: Int = Magician.magic(magic$param$1 _) 
} 

Поведение параметра call-by-name аналогично для определения метода без параметров - ссылки либо результатов в методе называют:

def paramlessMethod = 3 + 3 
def callByName(param: => Int) = param + paramlessMethod 
def test() = callByName(5 + 5) // 16, always 

В обоих случаях, вы можете «поднять» метод к Function0 (или «отложить оценку метода», если вы предпочитаете думать об этом, что путь) с помощью магии _:

def paramlessMethod = 3 + 3 
val functionWrapper: Function0[Int] = paramlessMethod _ 
functionWrapper() // 6 

def callByName(param: => Int) = param _ 
val functionFromParam: Function0[Int] = callByName(3 + 3) 
functionFromParam() // 6 
+0

Я не знаю, почему вы сказали бы, что '=> Int' не является типом или просто синтаксисом. –

+0

@ som-snytt - я бы не сказал, что у него нет типа, но тип не тот, который вы можете создать каким-либо другим способом (это тип, внутренний для компилятора). Поэтому я решил, вместо того, чтобы сосредоточиться на тишине '=> T', чтобы попытаться представить ее как синтаксическое преобразование, чтобы убедиться, что это помогает. –

+1

Я понимаю, что вы имеете в виду, но вы можете перегрузить 'f (i: Int)' и 'f (i: => Int)', поэтому это не теоретический или артефакт реализации. Это настоящий тип. Тот факт, что вы не можете использовать его в типе, подобном 'f (42: => Int)', не меняет этого. –

1

Тип def i: Int объясняется здесь:

http://www.scala-lang.org/files/archive/spec/2.11/03-types.html#method-types

типа-имя параметр i: => Int объясняется здесь:

http://www.scala-lang.org/files/archive/spec/2.11/04-basic-declarations-and-definitions.html#by-name-parameters

типа такого параметра, то типа метода без параметров => Т.

Другими словами, это то же, что метод типа def i: Int.