2011-05-22 30 views
4

根據文檔,None對象旨在「表示不存在的值」。據我所見,它主要用作空的Option。但是,你認爲將它用於其他目的是個好主意。舉例來說,在我的圖書館我希望有需要可能被分配給不同的缺失值,在這裏我也只是含蓄的「空」值轉換爲我的類型的通用的「空」的對象:Scala:將None用於除空之外的其他目的選項

// In library: 
trait A { 
    implicit def noneToT1(none: Option[Nothing]): T1 = defaultT1 
    implicit def noneToT2(none: Option[Nothing]): T2 = defaultT2 
    def f1: T1 
    def f2: T2 
} 
// In the code that uses the library 
class EmptyA extends A { 
    def f1 = None  
    def f2 = None  
} 

一以這種方式使用None的不(錯)的原因在於用戶預期f1f2分別返回Option[T1]Option[T2]。而他們沒有。當然,我可以有def f1: Option[T1],但在這種情況下,這些值實際上並不是可選的,它們只能有一些默認的空值或實際值,我只是想創建「引擎蓋下」的默認值並且有一些統一的通過整個圖書館說「默認」或「空」的方式。所以問題是,我應該使用None來表達這種「默認性」還是使用某種自定義類型?現在我用我自己的object Empty,但感覺有點多餘。

編輯: 要ilustrate我的問題,我將添加我使用的是現在的代碼:

// In library: 
trait Empty 
object Empty extends Empty 

trait A { 
    implicit def emptyToT1(none: Empty): T1 = defaultT1 
    implicit def emptyToT2(none: Empty): T2 = defaultT2 
    def f1: T1 
    def f2: T2 
} 
// In the code that uses the library 
class EmptyA extends A { 
    def f1 = Empty 
    def f2 = Empty 
} 
class HalfFullA extends A { 
    def f1 = Empty 
    def f2 = someValue2 
} 
class FullA extends A { 
    def f1 = someValue1 
    def f2 = someValue2 
} 

我的問題很簡單:這是使用Scala的None,而不是一個好主意,我Empty

回答

1

如果你不能或不想用繼承來定義默認值,我建議保留新的對象。重複使用None作爲別的東西而不是Some似乎是錯誤的,並不能真正爲您節省很多。

7

我只想用類型類此:

trait WithDefault[T] { 
    def default: T 
} 

object WithDefault { 
    // if T1 is an existing class 
    implicit val t1Default = new WithDefault[T1] {def default = defaultT1} 
} 

//if T2 is your own class: 
class T2 ... 
object T2 { 
    implicit val withDefault = new WithDefault[T2] {def default = defaultT2} 
} 

然後在方便的地方:

def default[T : WithDefault] = implicitly[WithDefault[T]].default 

及用途:

class EmptyA { 
    def f1 = default[T1] 
    def f2 = default[T2] 
} 

更新:要accomudate Vilius,可以試試這個:

def default = new WithDefault[Nothing]{def default = error("no default")} 

implicit def toDefault[U, T](dummy: WithDefault[U])(implicit withDefault: WithDefault[T]): T = withDefault.default 

class EmptyA { 
    def f1: T1 = default 
    def f2: T2 = default 
} 

這比OP的原始嘗試有好處,因爲每個新類都可以定義自己的默認值(以及WithDefault中的其他值),而不是將所有內容都放在特徵A中。

但是,這不起作用。見https://issues.scala-lang.org/browse/SI-2046

要解決此問題:

trait A { 
    def f1: T1 
    def f2: T2 

    implicit def toT1Default(dummy: WithDefault[Nothing]) = toDefault[T1](dummy) 
    implicit def toT2Default(dummy: WithDefault[Nothing]) = toDefault[T2](dummy) 
} 

class EmptyA extends A { 
    def f1 = default 
    def f2 = default 
} 
+0

這是一個很好的解決方案,我沒有想到它。我喜歡它,因爲您有創建默認值的統一方式,但仍不會混淆用戶對方法的類型。然而在這個特定的庫中,這會有點矯枉過正,並且仍然看起來很醜 - 例如,我的一些方法返回部分函數,​​所以我必須編寫:'default [PartialFunction [SomeType,OtherType]](當然我可以輸入別名,但那會是事件更多的矯枉過正) – 2011-05-23 06:07:56

+0

在這種情況下,Scala不能推導出類型參數嗎? – 2011-05-23 10:32:24

+0

更新了我的答案。 Scala不能推導出類型,因爲如果推斷出表達式類型並從中獲取方法的返回類型,則不會相反。 – IttayD 2011-05-23 10:57:56

3

我覺得你應該去的東西要簡單得多。舉例來說,從你的榜樣,並刪除多餘的東西,我們很快到達,

trait A { 
    def noT1 = defaultT1 
    def noT2 = defaultT2 
    def f1: T1 
    def f2: T2 
} 

class EmptyA extends A { 
    def f1 = noT1  
    def f2 = noT2  
} 

我真的沒有看到,添加選項或implicits這會增加任何價值,至少不會,除非有一些其他未說明的問題背景。

+0

問題是,我想用一個單詞來表示'noT1'和'noT2',可能還有許多其他的'noXX',這些單詞將通過我的庫統一。在某些情況下,這可以是一個空列表或集合,在其他情況下,可以是執行某些默認「空」操作的部分函數或其他。我想在一些神奇的單詞表達式下隱藏所有'Nil','Set.empty'或'{case _ =>}'。問題是,爲了這個目的,我應該使用'None'還是發明一些其他的東西(我現在要做的 - 我使用'Empty'對象)? – 2011-05-23 05:55:25

相關問題