2017-09-12 62 views
5

任何人都可以提供关于如何通过Scala编译器将名称参数=> TFunction0参数() => T转换为另一个的权威答案吗?我知道它们并不相同,但差别非常微小,因为它们可以在许多场景中互换使用。Scala:函数0与名称参数

示例:如果我定义

def someFunction: Int = 2 
def f(x: => Int): Unit = println(x) 

然后我可以成功地调用

f(2) 
f(someFunction) 

如何是() => Int用于=> Int可接受的置换?

更一般地说,() => T是一个普遍接受的替代名称为=> T的参数吗?

另外,请纠正我,如果我错了以下的理由:=> T是从不为() => T可接受的替代,因为第一个是值类型(T),另一种是功能型。也就是说,如果我有def f(x:() => Int),我将永远无法通过Int或懒惰Int(因为没有懒惰类型,所以甚至没有意义)。

+5

你的例子绝对*不*等价。第一个产生一个'Try [()⇒Int]',第二个'Try [Int]'。 '()⇒Int'的函数参数被转换为'⇒T',其中'T'为'()⇒Int'。 –

+0

这里有一些很好的信息:https://tpolecat.github.io/2014/06/26/call-by-name.html – nevets1219

+0

它们不会相互替换,它们也不会被Scala编译器转换为另一个。它们只是不同的东西,通常用于不同的目的。 –

回答

3

好的,这里是完整的细分。

def value: Int = ??? 
def method(): Int = ??? 

def f1(f:() => Int) = ??? 
def f2(f: => Int) = ??? 

f1(value) // fails 
f1(method) // works 
f2(value) // works 
f2(method) // works with a warning "empty-paren method accessed as parameterless" 
  1. F1(值)

因为f1期待一个单位=> Int函数,但是未给出一个Int值这一个失败。

  • F1(方法)

  • 这一个工作,因为f1期待的功能,并且被给予的方法。以下是区别:方法在Scala中不是一个值;它不能独立存在,并且是它在(类,特征,对象等)中定义的上下文的属性。函数是一个值;它可以保存在一个集合中,作为另一个函数的参数,从一个函数返回等等。当编译器期待一个函数并给出一个方法时,它将执行eta expansion。给定一个函数f: (a: Int, b: Int) => Int,eta扩展是在保留签名的同时创建另一个层的过程,因此它变成(a: Int, b: Int) => f(a, b)。这种技术很有用,因为我们可以将方法转换为函数。给定一些方法def f(a: Int): Int = ???,我们可以执行eta-expansion来创建类型为Int => Int的函数:(a: Int) => f(a)。如果你有兴趣,我前一段时间写了一个关于这个的blog post

  • F2(值)

  • 作品没有惊喜,但要注意的是,传递的值被访问每它在所用时间的事实功能体。

  • F2(方法)

  • 工程,但与我们所调用的方法是通过使用与空括号限定的警告无插入语。好的做法是在它们只是表示一个值时使用没有括号的方法(例如f),但是每次访问它时都会重新计算一个值,例如,当执行某种副作用并因此该方法不是幂等的时,使用带有空括号的方法(例如f())。 createSnapshot()(同样,这不应该出现在纯功能代码中)。

    建议的意思:不要用什么替代什么,不要使用替换品。如果某件事需要一个功能,请为它提供一个功能。如果它需要一个值,请提供一个值。如果一个方法没有parens定义,调用它没有parens。如果它有parens,请用parens调用它。

    如果你需要从一个方法到另一个功能并且编译器期望一个函数,eta-expansion将自动发生。如果它不期待功能,则需要手动完成。

    def f(): Int = ??? 
    val a = f    // no function context; a is a string 
    val b:() => Int = f // b is a function Unit => Int 
    val c = f2 _   // c is a function Unit => Int 
    

    最后一种情况下是一个部分应用功能。我觉得我现在过于宽泛,所以我会停下来。我希望这有助于。