2014-09-24 88 views
0

我希望能夠傳遞「無」的可選原因。我嘗試了延長「無」恩:擴展選項w /原因

case class NoneReason(reason: String) extends None 

卻得到了一個「未發現:類型無」,然後我想:

case class NoneReason(reason: String) extends Option[Nothing] { 
    def isEmpty = true 
    def get = throw new NoSuchElementException("None.get") 
} 

,但我從密封類選一「」非法繼承「

我猜這是一個特殊的情況,因爲‘無’實際上是空或東西的別名。

我認爲複製選項源,並將其重命名爲TriOption或東西,但日似乎很難維持。什麼將是一個優雅的方式來解決這個問題?

+5

您可以使用'Try [T]'或'Either [String,T]'而不是創建自己的類型。 – Lee 2014-09-24 21:17:32

+0

沒有特殊情況,'None'不是任何別名,尤其不是'null'的別名。所有'Option'類都是密封的,最終的或者case對象,這些都是你的意圖,你不應該能夠擴展這些,你不能。一個簡單的例子是'Option(something)match {case Some(x)=> ... case None => ...}'編譯器可以檢查您是否匹配了所有可能的情況,因爲'Option'不是可擴展到基礎包之外。正如@Lee所建議的,你應該使用不同的數據結構,比如'Either [String,T',它基本上是你的'NonReason'類型。 – Noah 2014-09-24 21:23:53

+0

子類型不是慣用的FP;此外,它使代碼更復雜,並禁用了例如匹配情況靜態耗盡檢查。 – 2014-09-25 12:17:42

回答

4

None的一個可選原因是Either[Option[String], Foo],其中Foo是您的類型。您不能延伸None;這是一個單身人士,所以你可以認爲它是一個值,如null

但是Either類用於在兩個選擇之間進行選擇,按照慣例包含「正確」答案的正確分支(如果一個比另一個更正確)。如果你想要一個可選的錯誤信息,那就在左邊的分支中。因此,您可以切換到上面顯示的類型,然後切換到任何您通常使用的位置Option,您可以將x.right.toOption轉換爲不帶消息的選項,或使用模式匹配或其他任何方式,例如

x match { 
    case Right(foo) => useFoo(foo) 
    case Left(None) => throw new Exception("Something went wrong.") 
    case Left(Some(msg)) => throw new Exception(msg + " went wrong.") 
} 

如果你覺得這有太多的樣板,你可以使用ScalaUtilsScalaz或任何一個數字,有一個選項與 - 原因替代其他庫的。 ScalaUtils非常容易上手。斯卡拉斯要深得多,如果你需要的深度真棒,並且如果你不意味着開始提高生產力需要更長的時間。

+0

對於ScalaUtils Or&Every而言+1 – Jean 2014-09-25 07:32:47

0

無不是空的別名。它是一個擴展了Option [Nothing]的對象(單例)。
您無法擴展它的原因是Option是密封類,這意味着它只能通過與密封類相同的文件中的類進行擴展。
正如Lee在您的問題的評論中所寫的那樣,要走的路是使用Try[T]Either[String, T]
Here一些很好的解釋如何使用它們。