Is there any workaround to create a dictionary with Optional keys? I know a proper solution for this would require Conditional Conformances to be implemented, but do I have any options before then?
let dict: [Int?: Int] = [nil: 1]
// ERROR: type 'Int?' does not conform to protocol 'Hashable'
Conditional conformances have been implemented in Swift 4.2, woohoo! 🎉
This allowed for Optional to be made conditionally Hashable, when the wrapped element is Hashable. So you can use any Optional<T: Hashable> as a dictionary key, directly!
let d: [Int?: String] = [
nil: "nil",
1: "a",
2: "b",
3: "c",
]
for (key, value) in d {
let stringKey = key.map(String.init(describing:)) ?? "nil"
print("\(stringKey): \(value)")
}
Here's one workaround I found: Create a new HashableOptional enum:
enum HashableOptional<Wrapped: Hashable> {
case none
case some(Wrapped)
public init(_ some: Wrapped) {
self = .some(some)
}
public init(_ optional: Wrapped?) {
self = optional.map{ .some($0) } ?? .none
}
public var value: Wrapped? {
switch self {
case .none: return nil
case .some(let wrapped): return wrapped
}
}
}
extension HashableOptional: Equatable {
static func ==(lhs: HashableOptional, rhs: HashableOptional) -> Bool {
switch (lhs, rhs) {
case (.none, .none): return true
case (.some(let a), .some(let b)): return a == b
default: return false
}
}
}
extension HashableOptional: Hashable {
var hashValue: Int {
switch self {
case .none: return 0
case .some(let wrapped): return wrapped.hashValue
}
}
}
extension HashableOptional: ExpressibleByNilLiteral {
public init(nilLiteral: ()) {
self = .none
}
}
And then you can use it like so:
let dict: [HashableOptional<Int>: Int] = [nil: 1]
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With