[英]Swift abstraction for enums with associated value
我有一個帶有關聯值ConfigurationValue
的枚舉,它存儲在 map 中。 對於每個可能的枚舉值,我都有特定類型的 getter。
如何最小化這些 getter 之間的代碼重復
enum ConfigurationValue {
case bool(Bool)
case int(Int)
case string(String)
}
var map: [T:ConfigurationValue] = [:]
public mutating func set(key: T, _ value: Bool) {
map[key] = .bool(value)
}
public mutating func set(key: T, _ value: Int) {
map[key] = .int(value)
}
public mutating func set(key: T, _ value: String) {
map[key] = .string(value)
}
private func getValue(key: T) -> ConfigurationValue? {
return map[key]
}
public func get(key: T) -> Bool? {
guard let value = getValue(key: key),
case .bool(let innerValue) = value else {
return nil
}
return innerValue
}
public func get(key: T) -> Int? {
guard let value = getValue(key: key),
case .int(let innerValue) = value else {
return nil
}
return innerValue
}
public func get(key: T) -> String? {
guard let value = getValue(key: key),
case .string(let innerValue) = value else {
return nil
}
return innerValue
}
枚舉似乎不是這里工作的正確工具,因為您可以通過僅轉換值來獲得相同的有用性(盡管不可否認,您不會從詳盡的開關錯誤中受益)。 如果您想使用 generics 來減少其中的一些重復,我會在 go 周圍使用 map 的包裝器,如下所示:
protocol Configurable {}
extension Int: Configurable {}
extension Bool: Configurable {}
extension String: Configurable {}
class ConfigurationMap<Key: Hashable> {
private var map = [Key: Configurable]()
func getValue(at key: Key) -> Configurable? {
return map[key]
}
func setValue(_ value: Configurable, at key: Key) {
map[key] = value
}
}
這里Key
將取代你的T
通用。 要合並更多數據類型,只需將要使用的類型擴展為Configurable
。 如果您不介意變異方法, ConfigurationMap
也可以是一個結構。
在 Swift 中,這不稱為“地圖”,而是稱為“字典”。 類型限制可以通過協議和顯式類型檢索來實現。
public protocol ConfigurationValue { }
extension Int: ConfigurationValue { }
extension Bool: ConfigurationValue { }
extension String: ConfigurationValue { }
public struct ConfigurationDictionary<Key: Hashable> {
private var dictionary: [Key: ConfigurationValue] = [:]
}
public extension ConfigurationDictionary {
subscript<Value: ConfigurationValue>(key: Key) -> Value? {
get { dictionary[key] as? Value }
set { dictionary[key] = newValue }
}
}
var configurationDictionary = ConfigurationDictionary<String>()
configurationDictionary["i"] = 1
configurationDictionary["i"] as Int? // 1
configurationDictionary["i"] as Bool? // nil
configurationDictionary["b"] = true
let b: Bool? = configurationDictionary["b"] // true
let i: Int? = configurationDictionary["b"] // nil
我不會使用協議,而是在ConfigurationValue
中添加兩個方法,第一個創建配置值,另一個獲取案例的內部值。
enum ConfigurationValue {
case bool(Bool)
case int(Int)
case string(String)
static func with<Value>(value: Value?) -> ConfigurationValue? {
if let value = value as? Bool {
return .bool(value)
}
if let value = value as? Int {
return .int(value)
}
if let value = value as? String {
return .string(value)
}
return nil
}
func get<Value>(ofType type: Value.Type = Value.self) -> Value? {
switch self {
case .bool(let bool):
return bool as? Value
case .int(let int):
return int as? Value
case .string(let string):
return string as? Value
}
}
}
let boolValue: Bool? = ConfigurationValue.bool(false).get() // Optional(false)
let intValue: Int? = ConfigurationValue.bool(false).get() // nil
let stringValue: String? = ConfigurationValue.bool(false).get() // nil
let boolConfiguration: ConfigurationValue? = .with(value: true) // bool(true)
let intConfiguration: ConfigurationValue? = .with(value: 42) // int(42)
let stringConfiguration: ConfigurationValue? = .with(value: "42") // string("42")
let doubleConfiguration: ConfigurationValue? = .with(value: 42.0) // nil
現在你可以避免樣板,假設你有一個 struct Foo
:
struct Foo<T: Hashable> {
var map: [T:ConfigurationValue] = [:]
mutating func set<Value>(_ value: Value?, forKey key: T) {
map[key] = .with(value: value)
}
func get<Value>(key: T) -> Value? {
guard let value = map[key] else {
return nil
}
return value.get()
}
}
var map: [String:ConfigurationValue] = [
"bool": .bool(false),
"int": .int(0),
"string": .string("string")
]
var bar = Foo(map: map)
var bool: Bool? = bar.get(key: "bool") // Optional(false)
var int: Int? = bar.get(key: "int") // 0
var string: String? = bar.get(key: "string") // string
bar.set(true, forKey: "bool")
bool = bar.get(key: "bool") // Optional(true)
bar.set(42, forKey: "int")
int = bar.get(key: "int") // 42
bar.set("Hello World!", forKey: "string")
string = bar.get(key: "string") // Hello World!
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.