I want to write Optional
extension for any types.
My code for integer:
extension Optional where Wrapped == Int {
func ifNil<T>(default: T) -> T {
if self != nil {
return self as! T
}
return default
}
}
var tempInt: Int?
tempInt.ifNil(default: 2) // returns 2
tempInt = 5
tempInt.ifNil(default: 2) // returns 5
It works but it is Optional(Int)
extension (Optional where Wrapped == Int
), I want to use this extension for any types like Date
, String
, Double
etc.
What are your suggestions?
The answer to your basic question is to just remove the where
clause:
extension Optional {
// ... the rest is the same
func isNil<T>(value: T) -> T {
if self != nil {
return self as! T
}
return value
}
}
Now it applies to all Optionals.
But this code is quite broken. It crashes if T
is not the same as Wrapped
. So you would really mean a non-generic function that works on Wrapped
:
extension Optional {
func isNil(value: Wrapped) -> Wrapped {
if self != nil {
return self! // `as!` is unnecessary
}
return value
}
}
But this is just an elaborate way of saying ??
(as matt points out)
extension Optional {
func isNil(value: Wrapped) -> Wrapped { self ?? value }
}
Except that ??
is much more powerful. It includes an autoclosure that avoids evaluating the default value unless it's actually used, and which can throw
. It's also much more idiomatic Swift in most cases. You can find the source on github.
public func ?? <T>(optional: T?, defaultValue: @autoclosure () throws -> T)
rethrows -> T {
switch optional {
case .some(let value):
return value
case .none:
return try defaultValue()
}
}
But I can imagine cases where you might a method-based solution (they're weird, but maybe there are such cases). You can get that by just rewriting it as a method:
extension Optional {
public func value(or defaultValue: @autoclosure () throws -> Wrapped) rethrows -> Wrapped {
switch self {
case .some(let value):
return value
case .none:
return try defaultValue()
}
}
}
tempInt.value(or: 2)