2014-04-23 29 views
3

道歉,如果這是一個新手的問​​題... 在Scala中我明白,這是最好使用Option而不是返回null,當你有一個返回實例,但可能會返回任何一個功能。我明白,這使得它更好的安全問題,因爲你沒有傳遞空引用,並冒着NullPointerException的風險。選項有更清晰的代碼

但是,有沒有比使用模式匹配更清晰的方式來處理選項? 我最終使用的語法如下:

val optObj : Option[MyObject] = myFunctionThatReturnsOption 
optObj match { 
    case Some(obj) => { 
    //my code using obj 
    } 

    case None => _ 
} 

在現實中,所有該做的是Java版本的等價物:

MyObject obj = myMethodThatCanReturnNull() 
if (obj != null) { 
    //my code using obj 
} 

有一些其他的方式來避免這一切的樣板斯卡拉當使用Option而不是null時引用?我只想執行一段代碼,只要Option包含一些對象(即不是None)。

+0

'Option'是*不*關於安全的實際;這是關於能夠更容易地處理缺失的值。 –

+0

是的,但很容易是一個模糊的術語。擁有'if(obj!= null){} else {}'絕對容易(可以說更容易)。使用Scala的原因是以類型安全和更正確的方式來支持這些事情...... :) – jbx

+0

如果不是null ... else null,如果你做了一次,那麼很容易,但如果你有一系列可以返回'null';此外,我甚至會說'foo.map(_。bar)'* * * * * * * *比* if(foo!= null)foo.bar else null更短,並且在一段時間之後可讀性更強。 –

回答

8

如果您想以更一致的方式工作,請使用foreach,getOrElse和/或map。下面是一些使用情況以及我會怎麼做:

//I want to get a non-null value and I have a sane default 
val result = myOption getOrElse 3 

//I want to perform some side effecting action but only if not None 
myOption foreach{ value => 
    println(value toString()) 
} 
//equivalently 
for(value <- myOption){ 
    //notice I haven't used the "yeild" keyword here 
} 

//I want to do a computation and I don't mind if it comes back as an Option 
val result = for(value <- myOption) yield func(value) 
val equivalent = myOption map func 

第三個例子會在兩種情況下使用map

它變得非常有趣,當你可以混合,並在「爲理解」相匹配的東西讓我們說func也返回Option但我只希望事情在特定的情況下工作(谷歌的術語。):

val result = for{ 
    value <- myOption if value > 0 
    output <- func(value) 
} yield output 

現在我得到一個Option但只有當myOption包含一個大於零的整數。漂亮漂亮的東西,不是嗎?

+1

謝謝,'for'方法(第二個)看起來也很乾淨。我不喜歡這樣一個事實,即當「Option」中只有一個值時,他們稱之爲「foreach」的第一個方法,使得像我這樣的新手難以讀取,但至少它比模式匹配更清晰。 – jbx

+1

@wheaties:我想你忘了添加一個'flatMap'的例子。 –

+1

@jbx:這是一個已知的問題(許多人並不認爲這是一個問題,但我確實)認爲「for」並不是真正的完美單詞; Haskell使用更加中立的'do'來代替。 –

3

您可以使用foreach,如果你只是想和值執行一些副作用的操作:

optObj.foreach(obj => { 
    //my code using obj 
}) 

如果你有一些其他使用情況,你應該用一些其他的方法上OptionmapfiltergetOrElse

+0

噢,出於某種原因,我將'forEach'與像Lists這樣的可迭代事物聯繫起來,這就是爲什麼我錯過了它...... Scala的方法命名有時候會變得如此晦澀難懂!是的'getOrElse'我很熟悉,但在這種情況下,模式匹配會更好(對於我的情況),因爲在get'返回值的正常情況下無法執行副作用。 – jbx

+0

命名與其他容器一致。把'Option'想象成一個容器,它可以容納一個或零個項目。 –

1

當然,我通常使用的選擇,如果我只在乎現值的方法是的foreach:

optObj.foreach { obj => 
//... 
} 

話雖如此,還有很多其他的選項(@wheaties士兵)和一些人繼續與真實的爭鬥。

1

您可以使用flatMap-方法很好,Option。像票數:

case class Player(name: String) 
def lookupPlayer(id: Int): Option[Player] = { 
    if (id == 1) Some(new Player("Sean")) 
    else if(id == 2) Some(new Player("Greg")) 
    else None 
} 
def lookupScore(player: Player): Option[Int] = { 
    if (player.name == "Sean") Some(1000000) else None 
} 

println(lookupPlayer(1).map(lookupScore)) // Some(Some(1000000)) 
println(lookupPlayer(2).map(lookupScore)) // Some(None) 
println(lookupPlayer(3).map(lookupScore)) // None 

println(lookupPlayer(1).flatMap(lookupScore)) // Some(1000000) 
println(lookupPlayer(2).flatMap(lookupScore)) // None 
println(lookupPlayer(3).flatMap(lookupScore)) // None 
+0

不知道爲什麼你要顯示那裏的前3個'println's ......在這種情況下,你幾乎總是需要'flatMap'。 –

+0

@ErikAllik我想他想告訴我使用'map'和'flatMap'的區別,也就是說它提取了選項 – jbx

+0

啊,這是真的:) –