2015-12-08 3 views
-1

Скажем, я пишу метод, который принимает функцию, и имеет другую функцию, которая возвращает функцию. Я могу написать мой метод, как так:В чем разница между `() =>` и `=>`?

def logParens(f:() => String) = println(f()) 

Или вот так:

def logNoParens(f: => String) = println(f) 

И скажем, у меня есть метод, который возвращает строку

def foo = "foo" 

Каким образом я могу передать Foo непосредственно в logNoParens, но не logParens? Похоже, Scala заставляет foo в => foo перед тем, как передать его в logNoParens.

logParens(foo) // this gives me a type error 
logParens(() => foo) // this compiles 
logNoParens(foo) // this compiles just fine 

В чем разница между => и () =>?

+0

http://stackoverflow.com/questions/4543228/whats-the-difference-between-and-unit, на который ссылается амбициозный http://stackoverflow.com/tags/scala/info –

+0

Добавить parens to def foo() ', чтобы получить расширение eta. –

+0

Спасибо, @ som-snytt. Этот вопрос довольно сложный для Google. – bioball

ответ

0

короче: () ⇒ String создает функцию типа Unit ⇒ String в то время как ⇒ String означает ленивого значения типа String передается в качестве аргумента, поэтому она не переоценена позже в теле функции, если ссылка.

Так будет оценена только раз когда исполнение достигает его ссылки в коде, и не тогда, когда передается в качестве аргумента.

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

def func(f: ⇒ String) : Either[Exception, String]{ 
    if (someCondition) { 
    Right(f) 
    } else { 
    Left(new IllegalArgumentException("F can't be evaluated") 
    } 
} 

И возможное применение:

def doF() { 
    func { 
    io.Stream.fromFile("path/to/file") 
    } 
} 

конечно можно переписать следующим образом:

def func(f:() ⇒ String) : Either[Exception, String]{ 
    if (someCondition) { 
    Right(f()) 
    } else { 
    Left(new IllegalArgumentException("F can't be evaluated") 
    } 
} 

И возможное применение:

def doF() { 
func { 
    case _ ⇒ io.Stream.fromFile("path/to/file") 
    } 
} 

В зависимости от контекста вы можете выбрать прежнюю или последнюю форму, которые полностью взаимозаменяемы в случаях, описанных выше. Единственное отличие состоит в том, что если вы передадите значение lazy функции - он будет оцениваться только один раз, но если вы передадите функцию ссылки на функцию - будет выполнена функция и результат оценки передал функции столько раз, сколько используется в функции.

+0

Кажется, что он оценивается каждый раз, когда он ссылается внутри тела функции. 'def log (x: => Int) = от 1 до 3 foreach {_ => println (x)}; var z = 0; log {z = z + 1; z} ' В этом примере журналы 1, 2, 3 – bioball

Смежные вопросы