不透明型別是 Elm 中的一種封裝技巧。
有些人也稱它為資訊隱藏,也就是把實作細節藏起來。
它們也常被用來強制執行驗證,採用 Parse, dont validate 模式。
舉例來說,你可以有一個EmailAddress不透明型別,它只能包含有效的電子郵件地址(相對於String,它可以包含任何內容)。
自訂型別有一或多個變體,而編譯器會自動產生一個函式來建立每個變體,用的就是變體的名稱。 自訂型別也只能透過這種方式建立。 編譯器也允許對這些變體進行解構。
type Maybe a
= Nothing --> Variant implies a 'Nothing' function, with type 'Maybe a', and destructuring of 'Nothing'
| Just a --> Variant implies a 'Just' function, with type 'a -> Maybe a', and destructuring of 'Just _'
預設情況下,這些全都是檔案或模組內部的,我們用exposing關鍵字來選擇要匯出什麼。
Maybe模組會公開Maybe型別(讓其他模組可以使用既有的Maybe值),也會公開Nothing和Just變體(讓其他模組可以建立並解構Maybe值)。
它使用以下的語法來做到這件事。
Maybe(..)的部分告訴 Elm 要公開所有的變體,以及自訂型別的定義。
module Maybe exposing
( Maybe(..)
-- ...
)
要建立不透明型別,你只要選擇不匯出變體就好。
對Maybe型別來說,你會使用以下的語法:
module Maybe exposing
( Maybe
-- ...
)
這麼做的時候,你幾乎總是得提供另一種建立及取得變體的方式,也就是公開自訂函式。 這些自訂函式讓你在建立和取得變體時能套用一些邏輯。 這麼做會把模組內部的實作細節隱藏起來,也代表只要公開的函式維持不變,你可以隨意變更實作細節。 它也讓你在建立和使用這個型別時可以維持不變量。
不透明型別最常見的用途,大概就是用來強制執行驗證,採用 Parse, dont validate 模式。
在這個模式中,你公開一個函式,它接受的輸入結構或型別安全程度比你想要的低,例如String,然後把這個輸入解析成結構更完整的型別,例如EmailAddress,並且回傳該型別,或是回傳一個錯誤(通常是Maybe或Result)。
舉例來說,在下面的程式碼中,外部模組只能透過parseEmailAddress函式建立EmailAddress型別,所以當你在處理EmailAddress型別時,你就能確定它是有效的。
module EmailAddress exposing ( EmailAddress, parseEmailAddress, getEmailAddress )
-- The `EmailAddress` custom type has one variant, also called `EmailAddress`
-- When a custom type has one variant, it is idiomatic to use the same name for both.
type EmailAddress =
EmailAddress String
-- create an EmailAddress variant
parseEmailAddress: String -> Maybe EmailAddress
parseEmailAddress candidateEmailAddress =
if isValidEmailAddress candidateEmailAddress then
Just (EmailAddress candidateEmailAddress)
else
Nothing
-- get an EmailAddress variant
getEmailAddress: EmailAddress -> String
getEmailAddress ( EmailAddress emailAdress ) =
emailAdress
isValidEmailAddress: String -> bool
-- ...