2017-08-23 162 views
2

我是新来的scala。高阶函数后面的大括号或括号中是否有区别?.map(...)和.map {...}在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 }结果低于nd为什么'嗨'只是打印一次?

Hi 
List[Int] = List(2, 3) 
+0

完全重复https://stackoverflow.com/q/19591227/1296806但在这里是一个不错的答案。 –

回答

6

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 {} 

此外,还有由名参数来处理。通过名称参数声明如下所示:

def func(a: => String) // Not() => String, it's => String 

当你按名称参数,然后

func { println("x"); _ + 1 } 

实际上通过整个块作为参数。该块仍然评估为i => i + 1,但func控制发生评估。具体来说,块的代码变成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 

注意括号是如何各地块,这真的让这看起来像是定义控制流的能力省略运营商。

+0

太棒了!这真的很有帮助。 –

+0

好ascii艺术!请说“结果表达式”而不是块的“返回值”。块不是一个函数,它是一堆语句,最后是结果。我对上述链接问题的回答也表示“嗨”。 “嗨。”关于'list.map {x =>}的语法'请参阅https://stackoverflow.com/a/13873899/1296806 –

1

一般而言,将使用括号用于封闭简单功能参数:

l.map(x => x * 2) 

和花括号用于包围更复杂的代码块或部分功能,其包括case模式匹配:

l.map{ x => 
    val y = x * 2 
    y 
} 

l.map{ 
    case x if x%2 == 0 => x * 2 
    case _ => 0 
} 

至于Hi之所以只能打印一次,List(1, 2).map{ println("Hi"); _ + 1 }List(1, 2).map{ println("Hi"); x => x + 1 }没有什么不同。若要在map迭代println

List(1, 2).map{ x => println("Hi"); x + 1 } 
// Hi 
// Hi 
// res1: List[Int] = List(2, 3) 
相关问题