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,200评论 4 61
  • 早安, 眼前是云吗? 我这样问你,你微笑的样子好孤单。 你想着谁想了一晚? 你的眼在看什么方向? 闭上眼谁会在你身...
    易安阅读 329评论 0 4