回答
當然它不那麼邪惡!
如果不針對None進行檢查,那麼大多數情況下,應用程序中會出現類型錯誤,這意味着它不會編譯,因此它不會因NullReferenceException而崩潰(因爲None轉換爲null) 。
例如:
let myObject : option<_> = getObjectToUse() // you get a Some<'T>, added explicit typing for clarity
match myObject with
| Some o -> o.DoSomething()
| None -> ... // you have to explicitly handle this case
但仍可以實現類似C#的行爲,但它是不太直觀,因爲你必須明確地說:「忽略,這可能是無」:
let o = myObject.Value // throws NullReferenceException if myObject = None
在C#中,您不必強制將變量的情況視爲null,因此您可能只是忘記進行檢查。同上例如:
var myObject = GetObjectToUse(); // you get back a nullable type
myObject.DoSomething() // no type error, but a runtime error
編輯:斯蒂芬·斯文森是絕對正確的,我的例子代碼有一些缺陷,在匆忙中寫它。固定。謝謝!
即使在C#中,如果不檢查空值,您將在ReSharper中收到警告 – JoelFan 2010-12-17 11:27:36
@Carlo V. Dango,@SplashHit在使用選項類型時,您有非常方便的方法Option.Map和Option.bind,加上它會強制您處理無和理由。你也可以以安全的方式輕鬆擴展你的代碼,以防你想要比二進制Some(somthing)或None(nothing)更多的結果。 – jlezard 2010-12-17 11:48:57
@SplashHit:使用C#,您需要額外的(外部)幫助來管理空檢查。使用F#,Option類型使這部分語言成爲可能。 – pblasucci 2010-12-17 13:16:38
與null
的問題是,你必須使用它幾乎無處不在,即引進無效狀態,其中這是既不打算也不有道理的可能性。
有一個'a option
總是一個明確的事情。您聲明操作可以生成有意義的值Some
或None
,編譯器可以執行強制執行以進行正確檢查和處理。
通過阻止null
轉而支持'a option
類型,您基本上可以保證程序中的任何值都具有某種意義。如果某些代碼設計爲使用這些值,則不能簡單地傳遞無效代碼,並且如果存在option
類型的函數,則將有具有以涵蓋所有可能性。
這個答案是遠遠優於接受的一個伊莫(雖然都很好)。 ShdNx的回答涉及爲什麼選項很好,但是這個實際上將它與null比較,並回答它真的不那麼邪惡(甚至是太棒了!)。希望我能夠第二次投票;謝謝你達里奧! – MasterMastic 2014-01-28 17:44:40
比方說,我告訴你一個函數的定義是這樣的:
val getPersonByName : (name : string) -> Person
你覺得當你在誰不會在數據存儲存在的人的name
傳會發生什麼?
- 該函數是否會拋出NotFound異常?
- 它是否返回null?
- 如果他們不存在,它會創建人嗎?
閱讀代碼(如果您有權訪問它),閱讀文檔(如果有人足夠寫它)或者只是調用函數,您無法知道。這基本上是空值的問題:它們的外觀和行爲與非空值相同,至少在運行時纔會發生。
現在讓我們假設你有一個函數與此簽名改爲:
val getPersonByName : (name : string) -> option<Person>
這個定義可以很明確的會發生什麼情況:你要麼得到一個人回來,或者你不會和這種信息在函數的數據類型中傳遞。 通常,您可以更好地保證處理選項類型的兩種情況而不是可能的空值。
我會說選項類型比nulls更仁慈。
在f#中,也可以在給定這樣的函數聲明時拋出異常 – 2010-12-22 09:05:21
In F# its a big deal that they do not have null values and do not want to support it. Still the programmer has to make cases for None similar to C# programmers having to check != null.
Is None really less evil than null?
而null
介紹了運行時錯誤(NullRefereceException
)每取消引用在C#中,None
力量的對象,你使運行時錯誤在F#明確的來源時的潛在來源。
例如,一個給定的對象上調用GetHashCode
導致C#到靜默注入運行時錯誤的來源:
class Foo {
int m;
Foo(int n) { m=n; }
int Hash() { return m; }
static int hash(Foo o) { return o.Hash(); }
};
相反,在F#的等效代碼預計將null
自由:
type Foo =
{ m: int }
member foo.Hash() = foo.m
let hash (o: Foo) = o.Hash()
如果你真的想在F#中的可選值,那麼你可以使用option
類型,你必須明確地處理它,否則編譯器會給出警告或錯誤:
let maybeHash (o: Foo option) =
match o with
| None -> 0
| Some o -> o.Hash()
您仍然可以通過規避類型系統(這是需要互操作)獲得F#NullReferenceException
:
> hash (box null |> unbox);;
System.NullReferenceException: Object reference not set to an instance of an object.
at Microsoft.FSharp.Core.LanguagePrimitives.IntrinsicFunctions.UnboxGeneric[T](Object source)
at <StartupCode$FSI_0021>[email protected]()
Stopped due to error
這可能是一本關於禪的稱號! – TechNeilogy 2010-12-17 14:45:57
當然比'type bool = True |更好False | FileNotFound' – Juliet 2010-12-17 16:53:51
另請參見http://stackoverflow.com/questions/3989264/best-explanation-for-languages-without-null – Brian 2010-12-18 03:12:11