F# 之 Option 型別簡介

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

内容简介:當我們要根據使用者輸入的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


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

查看所有标签

猜你喜欢:

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

Beginning XSLT 2.0

Beginning XSLT 2.0

Jeni Tennison / Apress / 2005-07-22 / USD 49.99

This is an updated revision of Tennison's "Beginning XSLT", updated for the new revision of the XSLT standard. XSLT is a technology used to transform an XML document with one structure into another ......一起来看看 《Beginning XSLT 2.0》 这本书的介绍吧!

随机密码生成器
随机密码生成器

多种字符组合密码

HEX HSV 转换工具
HEX HSV 转换工具

HEX HSV 互换工具