带有关联类型的枚举的原始值初始化构造器
在 Swift 中,枚举(Enums)是一种优雅的结构化信息的方式。有时候你会发现自己需要通过原始值(raw values)来构造枚举,因为这些值可能零星地存储在某些地方,比如 enum Device: String { case Phone,Tablet,Watch } let aDevice = Device(rawValue: "Phone") print(aDevice) // 打印结果为: Optional(main.Device.Phone) 问题但只要你在枚举中用了关联值(associated values),这种方式就失效了。比如这样的枚举: enum Example { case Factory(workers: Int) case House(street: String) } 由于这个枚举的两个成员( 然而,就算所有成员的关联类型都相同,这种方法也不管用: enum Device { case Phone(name: String,screenSize: CGSize) case Watch(name: String,screenSize: CGSize) case Tablet(name: String,screenSize: CGSize) } 在这个例子中,所有关联类型(associated types)都是一样的——事实上,有很多种方式都能说明问题,但是我发现用 import Foundation enum Device { case Phone(name: String,screenSize: CGSize) static func fromDefaults(rawValue: String,name: String,screenSize: CGSize) -> Device? { switch rawValue { case "Phone": return Device.Phone(name: name,screenSize: screenSize) case "Watch": return Device.Watch(name: name,screenSize: screenSize) case "Tablet": return Device.Tablet(name: name,screenSize: screenSize) default: return nil } } } let b = Device.fromDefaults("Phone",name: "iPhone SE",screenSize: CGSize(width: 640,height: 1136)) print(b) // 打印结果为: Optional(main.Device.phone("iPhone SE",(640.0,1136.0))) 这看起来还好,但这些代码确实有些冗余了。一旦你需要创建的枚举中有着三个以上的枚举成员或者两种以上的关联类型,事情就会很快失控。 enum Vehicle { case Car(wheels: Int,capacity: Int,weight: Int,length: Int,height: Int,width: Int,color: Int,name: Int,producer: Int,creation: NSDate,amountOfProducedUnits: Int) case Ship(wheels: Int,amountOfProducedUnits: Int) case Yacht(wheels: Int,amountOfProducedUnits: Int) case Truck(wheels: Int,amountOfProducedUnits: Int) case Motorbike(wheels: Int,amountOfProducedUnits: Int) case Helicopter(wheels: Int,amountOfProducedUnits: Int) case Train(wheels: Int,amountOfProducedUnits: Int) // ... } 我想你明白我想表达的意思。 解决方法所以……我们应该怎么处理这种情况呢?有趣的是,在关联类型的初始化构造器(initializer)和闭包间有种迷之相似性。看看下面的代码: enum Example { case Test(x: Int) } let exampleClosure = Example.Test 代码中 这说明了下面的代码是正确的,能够正常工作: enum Fruit { case Apple(amount: Int) case Orange(amount: Int) } let appleMaker = Fruit.Apple let firstApple = appleMaker(amount: 10) let secondApple = appleMaker(amount: 12) print(firstApple,secondApple) // 打印结果为: Apple(10) Apple(12) 所以,这将如何帮助我们简化上面糟糕的代码重复问题呢?让我们来看看: import Foundation enum Device { case Phone(name: String,screenSize: CGSize) private static var initializers: [String: (name: String,screenSize: CGSize) -> Device] = { return ["Phone": Device.Phone,"Watch": Device.Watch,"Tablet": Device.Tablet] }() static func fromDefaults(rawValue: String,screenSize: CGSize) -> Device? { return Device.initializers[rawValue]?(name: name,screenSize: screenSize) } } let iPhone = Device.fromDefaults("Phone",height: 1134)) print(iPhone) // 打印结果为:Optional(main.Device.Phone("iPhone SE",1134.0))) 让我们试着指出这段代码做了什么。我们给 之后的 Device.initializers["Phone"]?(name: "iPhone 5",height: 1134)) 就像直接用原始值那样,如果枚举中没有 Phone 这个成员,则会返回一个空值。 当然,这个解决方案并不完美,我们仍然不得不使用 最后,我想,不用我多说的是,上面的代码忽视了一点——一个合格的最佳实践应该是简洁并能够让人专注于手上的工作的。然而,像是 如果你读到这儿了,我想你应该在 Twitter 上粉我(@terhechte)
(编辑:李大同) 【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容! |