2017-08-23 161 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) 
相關問題