Swift tricks-Phantom Types

Swift tricks系列收集Swift牛逼的patterns和讓你代碼更加Swifty的tricks,持續更新中……

Phantom Types

在項目中,某些業務是需要按照嚴格的流程和規范進行的,舉個??

func getSecretData() -> String {
    return "secretedata";
}
func encrypt(secretData : String) -> String {
    return "encryptdata";
}
func sendEncryptData(encryptdata : String){
    // send encrypt data
}
//首先獲取秘密信息
var secretedata = getSecretData()
//對秘密信息加密
var encryptdata = encrypt(secretedata)
//發送加密信息
sendEncryptData(encryptdata)

上面的例子必須嚴格按照“獲取信息”->“加密”->“發送”的流程來,否則就會產生安全問題!
但是程序員是人,是人就會犯錯誤。如果一個粗心的程序員寫了下面的代碼,那將會產生災難性的后果:

var secretedata = getSecretData()
sendEncryptData(secretedata)

腫么辦?能不能通過代碼來保證流程呢?Yes, we can!
一般的做法是醬紫的:

struct SecretData {
    let secretedata:String
}

struct EncryptData {
    let encryptdata:String
}

func getSecretData() -> SecretData {
    return SecretData(secretedata:"secretedata");
}
func encrypt(secretData : SecretData) -> EncryptData {
    return EncryptData(encryptdata:"encryptdata");
}
func sendEncryptData(encryptdata : EncryptData){
    // send encrypt data
}
var secretedata = getSecretData()
var encryptdata = encrypt(secretedata)
sendEncryptData(encryptdata)

這樣我們就能避免粗心程序員造成的錯誤 。因為當你試圖執行sendEncryptData(secretedata)的時候,編譯器會報錯!


在上面的方法中,我們定義了兩個struct,這兩個struct除了名字不一樣外,其他都是一模一樣。設想一下,如果struct里面的字段稍微多一點,我們的代碼將是這樣的:

struct SecretData {
    let secretedata:String
    let encyptMehod:String
    let encyptKey:String
    let from:String
    let to:String
    ......
}

struct EncryptData {
    let encryptdata:String
    let encyptMehod:String
    let encyptKey:String
    let from:String
    let to:String
    ......
}

這……就有點不怎么Swifty了。
腫么辦?


Phantom Types!

enum Encrypted {}
enum Decrypted {}

struct SecretData<T> {
    let secretedata:String
    let encyptMehod:String
    let encyptKey:String
    let from:String
    let to:String
}

func getSecretData() -> SecretData<Decrypted> {
    return SecretData(secretedata:"secretedata", encyptMehod:"nb", encyptKey:"xxx",from:"agent",to:"gcd");
}
func encrypt(secretData : SecretData<Decrypted>) -> SecretData<Encrypted> {
    return SecretData(secretedata:"secretedata", encyptMehod:"nb", encyptKey:"xxx",from:"agent",to:"gcd");
}
func sendEncryptData(encryptdata : SecretData<Encrypted>)
{
    // send encrypt data
}
var secretedata = getSecretData()
var encryptdata = encrypt(secretedata)
sendEncryptData(encryptdata)

EncryptedDecrypted是兩個Phantom Type,我們通過一個范型struct解決了重復定義屬性的問題。

PS:看到沒有case的enum不要驚訝,這是Phantom Type的精髓

參考:Functional Snippet #13: Phantom Types

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。

推薦閱讀更多精彩內容

  • 發現 關注 消息 iOS 第三方庫、插件、知名博客總結 作者大灰狼的小綿羊哥哥關注 2017.06.26 09:4...
    肇東周閱讀 12,257評論 4 61
  • 早安, 眼前是云嗎? 我這樣問你,你微笑的樣子好孤單。 你想著誰想了一晚? 你的眼在看什么方向? 閉上眼誰會在你身...
    易安閱讀 329評論 0 4