scala中的"code:=> Unit"是什么意思?

woo*_*ods 19 types scala

有没有人知道scala中=> Unit的类型?我不知道=> Unit的含义以及如何使用它.我定义了如下函数:

def test(code: => Unit){
   print("start ...")
   code
   print("end ....")
}

test(print(1))
Run Code Online (Sandbox Code Playgroud)

它是否意味着具有返回Unit的任何参数的函数?

谢谢

Mac*_*ndy 23

这种参数称为by-name参数

=> B表示返回B值的代码块a ,其目的是仅在调用参数时对它们进行求值.

def foo(code: => Int) {
    println("Not yet evaluated")
    val result = code
    println("parameter evaluated %s, is it an int ? %s " format (
           result, result.isInstanceOf[Int]) )
}
Run Code Online (Sandbox Code Playgroud)

您可以foo通过以下方式致电:

foo(1) 
Run Code Online (Sandbox Code Playgroud)

要么

val a = 3
val b = 5
foo {
  val c = a * a
  c * b
}
Run Code Online (Sandbox Code Playgroud)

另一种传递参数样式是按值:参数在发送到方法之前进行评估

def foo(code : Int) {
    println("Parameter already evaluated")
    val result = code
    println("parameter evaluated : " + result)
}
Run Code Online (Sandbox Code Playgroud)

参考

Scala中的Book Functionnal Programming中提取

说明了by-name参数和by-value参数之间的更多差异

  • 这不是一个好的答案,因为它没有区分by name参数和lazy(call by need)参数. (3认同)

Ben*_*son 13

x: => Typex按名称调用参数.这与采用不带参数的函数的参数不同: x: () => Type


Dan*_*ral 8

这称为名称参数,与名称参数评估策略相关.有关传递参数的相似但不相同的方法,请参阅链接的维基百科文章.

为了更好地解释它,让我们首先考虑两个最常见的参数评估策略:按值调用和按引用调用.

按价值呼叫是迄今为止最常见的评估策略.例如,它是Java中的唯一策略,也是C中的默认策略.例如,考虑这个简单的Java程序:

public class ByValue {
    static public void inc(int y) {
        y++;
    }

    static public void main(String... args) {
        int x = 0;
        inc(x);
        System.out.println(x);
    }
}
Run Code Online (Sandbox Code Playgroud)

它会打印0,因为它x的值被复制到y,所以当y递增时它不会改变原始值x.将此与此C++程序进行对比,并使用call-by-reference:

#include <stdio.h>

void inc(int &y) {
    y++;
}

int main() {
    int x = 0;
    inc(x);
    printf("%d\n", x);
}
Run Code Online (Sandbox Code Playgroud)

这将打印1,因为x引用被传递给inc,而不是x值.

请注意,Java按值传递对象引用,这导致一些人声称它通过引用调用.事实并非如此,如果您要将对象分配给函数的参数,它将不会反映在函数的调用者中.

那么,名字的呼叫是什么样的呢?在按名称调用时,既不传递值也不传递引用.相反,传递整个代码,并且在使用参数的任何地方,执行代码并使用其结果.例如:

object ByName {
  def incIfZero(y: => Int): Int = if (y == 0) y + 1 else y

  def main(args: Array[String]) {
    var x = 0
    x = incIfZero( { val tmp = x; x += 1; tmp } )
    println(x)
  }
}
Run Code Online (Sandbox Code Playgroud)

此示例打印2而不是1,因为作为参数传递的代码块被评估两次.执行时,就好像第二行main一样写成:

x = if ({ val tmp = x; x += 1; tmp }) { val tmp = x; x += 1; tmp } + 1 else { val tmp = x; x += 1; tmp }
Run Code Online (Sandbox Code Playgroud)

现在,通过名称参数至少有三个有趣的用途:

  1. 它可以用来延迟某事的执行,直到适当的时间.
  2. 它可以用来避免在某些情况下执行.
  3. 它可用于多次执行某些代码块.

我认为,第一个和最后一个案例非常明显.以下是第二种情况的示例:

implicit def fromBoolean(b: Boolean) = new { 
  def and(that: => Boolean): Boolean = if (b) that else b }
val x = 0
(x > 0) and (10 / x > 0)
Run Code Online (Sandbox Code Playgroud)

如果that不是by name参数,则会在最后一行抛出异常.事实上,它将会回归false.