scala中.map(...)和.map {...}之间的区别是什么

Lit*_*oys 5 scala

我是斯卡拉的新手.高阶函数跟随括号或括号块之间是否有任何差异?

例如:

  • List(1, 2, 3).map(i=> i + 1)

  • List(1, 2, 3).map {i => i + 1}

两者都得到相同的结果: List(2, 3, 4)

但是对于这个例子List(1, 2).map { println("Hi"); _ + 1 }结果如下,为什么'你好'只打印一次?

Hi
List[Int] = List(2, 3)
Run Code Online (Sandbox Code Playgroud)

HTN*_*TNW 9

Scala中的一个块只是一个表达式.与括号一样,它们对于将代码组合在一起非常有用.与括号不同,块不包含一个表达式,但可以包含一个或多个表达式.块的值是其中最后一个表达式的值.

{ println("Hi"); _ + 1 }相当于{ println("Hi"); (i: Int) => i + 1 }.这是一个打印出来的块,"Hi"它的值是一个添加一个的函数.执行退出块之前打印字符串,它生成的函数对该函数一无所知println.

以下是这些规则的一些示例:

list.map(i => i + 1)
//      ^----------^
//    function literal passed as argument

list.map(_ + 1)
//       ^---^
// Underscore shorthand for above

list.map({ i => i + 1 })
// Identical to above.
// The block only contains one expression, so it has the value of that expression
// Otherwise stated: { expr } === expr

list.map({ println("Hi"); _ + 1 })
//         ^-----2-----^  ^-3-^
//       ^------------1---------^
// 1: The argument to map is the value of this block
// 2: The first statement of the block prints something. This is only executed once,
//   because it's not the *block* being passed as argument, it's its value.
// 3: Function literal in underscore notation. This is the value of the block
//   and this is what map sees.
// Order of operations (approx. bytecode):
// load list onto stack
// load string "Hi" onto stack
// call println and pop string off stack
// create function (i => i + 1) on top of stack
// invoke map with argument (i => i + 1), popping list and function off stack

list.map { println("Hi"); _ + 1 }
// Identical to above, but Scala lets you omit the () because you are using {}

list.map({ i => println("Hi"); i + 1 })
// Function literals grow as big as they can be.
// The block contains only one expression, which is (i => println("Hi"); i + 1)
// This function prints "Hi" and then returns i + 1
// This call to map will print "Hi" for every element

list.map { i => println("Hi"); i + 1 }
// Identical to above, but Scala lets you omit the () because you are using {}
Run Code Online (Sandbox Code Playgroud)

此外,还有要处理的名称参数.按名称参数声明如下:

def func(a: => String) // Not () => String, it's => String
Run Code Online (Sandbox Code Playgroud)

当你有by-name参数时,那么

func { println("x"); _ + 1 }
Run Code Online (Sandbox Code Playgroud)

实际上将整个块作为参数传递.该块仍然评估i => i + 1,但func控制该评估何时发生.具体来说,块的代码变成a Function0并传入func,可以根据需要多次调用它,带有副作用.这可以用来产生很好的效果,基本上允许普通函数像自定义控制流操作符一样工作:

@tailrec def repeat(i: Int)(op: => Any): Unit
= if(i == 0) ()
  else {
    require(i >= 0, s"negative repeat amount: $i")
    op // Evaluate op
    repeat(i - 1)(op) // Won't evaluate op; will let sub-call deal with it
  }

repeat(5) { println("Hi"); println("Bye") }
// Hi
// Bye
// Hi
// Bye
// Hi
// Bye
// Hi
// Bye
// Hi
// Bye
Run Code Online (Sandbox Code Playgroud)

注意如何在块周围省略括号,这实际上使得它看起来像定义控制流操作符的能力.