F# 之 Option 型別簡介

栏目: ASP.NET · 发布时间: 7年前

内容简介:當我們要根據使用者輸入的C# 7.2F# 4.1

當我們要根據使用者輸入的 OrderId 到資料庫搜尋 訂單資料 ,若找的到就回傳該筆訂單,若搜尋不到呢?一般而言有兩種處理方式,傳回 null 或拋出 exception,但實務上常會因為忘記處理 null 或 exception,而在 run-time 得到 NullReferenceException ,這種常見的錯誤,是否能在 compile-time 獲得解決呢?

Version

C# 7.2

F# 4.1

Null

var order = Order.GetById(10);
Console.WriteLine("{0}", order.Name));

getById() 會根據 user 輸入的 OrderId ,到資料庫搜尋 訂單資料 ,junior 常會這樣寫程式。

這樣的寫法乍看之下沒問題,但 code review 時一定會被 sernior 問:

Q:若找不到訂單資料而回傳 null 該怎麼辦?

var order = Order.GetById(10);
if (order == null) 
{
    Console.WriteLine("No orders found.");
}
else 
{
    Console.WriteLine("{0}", order.Name));
}

Junior 會乖乖的補上 null 判斷,如此才不會在 run-time 得到 NullReferenceException

若使用 null 代表 找不到資料 ,會有幾個問題:

  1. 必須額外加上 null 判斷,否則在 run-time 會得到 NullReferenceException
  2. 因為 null 也是 Order 型別,所以 compiler 對於 null 檢查無能為力,只能靠 developer 自己的細心,或靠 unit test 的 coverage 完整加以保護
  3. 每個 function 都可能傳回 null ,是否每個 function 都必須判斷 null ?如此 code 會變得很髒

Exception

Q: null 的確不好,所以若找不到訂單資料就拋 exception 不就好了?

try
{
    var order = Order.GetById(10);
    Console.WriteLine("{0}", order.Name));
}
catch (OrderNotFoundException e)
{
    Console.WriteLine("No orders found.");
}

Exception 雖然比 null 好,但依然有些問題:

  1. getById() 回傳 Order 型別,你該如何得知到底該處理 null 還是要處理 exception?靠文件還是要靠團隊共識?
  2. 若 developer 忘記處理 exception,compiler 也無能為力,只能靠 developer 自己的細心,或靠 unit test 的 coverage 完整加以保護
  3. 每個 function 都可能傳回 exception,是否每個 function 都必須處理 exception? try catch 寫法其實也好不到哪裡,一樣會把 code 弄髒

Option

FP 語言對 null 與 exception 提出了另外一種解決方案,在 OCaml 與 F# 有 Option 型別,在 Haskell 有 Maybe 型別,讓我們可以在 compiler-time 就能處理,也不會把 code 弄髒。

open System

type Order = {
    Id: int
    Name: string
};

[<EntryPoint>]
let main argv =
    let getById id = Some { Id = 10; Name = "Sam" }
        
    let order = getById 10
    match order with
    | Some order -> printfn "%s" order.Name
    | None       -> printfn "No orders found."    
    
    0 // return an integer exit code

由於 getById() 可能傳回 訂單資料 ,也可能找不到資料,因此回傳的就不是 Order 型別,也不是 null ,而是另外一個 Order option 型別,也就是 Option<Order>

再搭配 Pattern Matching 對 Option 做處理,即可同時對 找到訂單資料找不到訂單資料 進行處理。

F# 之 Option 型別簡介

getById() 回傳的型別不再是 Order 型別 ,而是 Order option 型別,這是個 Option 型別。

Q:什麼是 Option 型別呢 ?

type Option<'a> =
    | Some of 'a
    | None

Option 事實上就是 Union 型別,只是已經是先定義好 SomeNone 兩個 case。

重點是 nullOrder 型別,但 None 不是 Order 型別,而是 Option 型別。

Q : Option 型別對於寫程式有什麼幫助?

之前因為 null 屬於 Order 型別,也無法確定 getById() 是否拋出 exception 而造成困擾,但若確認 getById() 回傳的是 Option 而不是 Order 型別,則 client 就有心理準備,知道要怎麼處理 Option ,不需靠文件也不需靠團隊共識。

let order = Order.getById 10
printfn "%s" order.Name

就算 junior 寫出這樣的程式碼,不用等 senior 來 code review,compiler 已經編譯錯誤,因為 orderOption 型別,不是 Order 型別,因此無法直接由 order.Name 取值。

F# 之 Option 型別簡介

因為 order 不是 Order 型別,所以沒有 Name 可取,在 Intellisense 階段就已經提出警告。

為了要從 Option 取值,就一定得搭配 Pattern Matching。

match order with
| Some order -> printfn "%s" order.Name
| None       -> printfn "No orders found."

透過 Pattern Match 的 Some 將 order 取出來。

F# 之 Option 型別簡介

若在 Pattern Matching 只寫了 Some ,忘記寫 None ,compiler 也會提出警告。

Summary

Option 型別具有以下優點

  1. 透過 Option 型別,client 可以明確得知該 function 可能傳回資料,也可能不傳回資料,因此會有明確因應對策,而不像 null 與 exception 那樣
  2. 由於 Option 型別不等於原本資料型別,因此 junior 無法直接對 Option 取值而造成 NullReferenceException
  3. 一定得用 Pattern Matching 處裡 Option 型別,若忘記使用 Pattern Matching 或 case 不夠完整,compiler 會在 compile-time 就加以警告,不會有忘記處理 Option 的問題
  4. Pattern Matching 遠比 null checkingexception handling 優雅,也不會把 code 弄髒

Conclusion

  • 好的程式語言是在 compile-time 就幫我們找到錯誤,而不是要自己寫程式在 run-time 處理
  • null 與 exception 除了常常忘記處理而造成 NullReferenceException , 也很容易將 code 弄髒;但 Option + Pattern Matching 則可透過 compiler 幫我們檢查,code 也比較優雅
  • JavaScript 已經有 Option 型別草案,希望能儘早成為 JavaScript 標準

Reference

Microsoft Docs , Options

F# for fun and profit , The Option type

David Raad , null is Evil

David Raad , Exceptions are Evil

David Raad , Optionals

David Raad , The Option Module


以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持 码农网

查看所有标签

猜你喜欢:

本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们

Programming Python

Programming Python

Mark Lutz / O'Reilly Media / 2006-8-30 / USD 59.99

Already the industry standard for Python users, "Programming Python" from O'Reilly just got even better. This third edition has been updated to reflect current best practices and the abundance of chan......一起来看看 《Programming Python》 这本书的介绍吧!

Base64 编码/解码
Base64 编码/解码

Base64 编码/解码

URL 编码/解码
URL 编码/解码

URL 编码/解码

Markdown 在线编辑器
Markdown 在线编辑器

Markdown 在线编辑器