How to add an optional string extension?
You can do it like this:
protocol OptionalType { typealias A; var opt: A? { get } }
extension Optional: OptionalType { var opt: A? { return self } }
protocol StringType { var get: String { get } }
extension String: StringType { var get: String { return self } }
extension Optional where Wrapped: StringType {
func getOrElse(s: String) -> String {
return self.opt?.get ?? s
}
}
And:
let optStr: String? = nil
optStr.getOrElse("hello world")
The reason that you cannot constrain Optional
or String
for that matter, is because they are struct
. By making pseudo-protocol for each, now we can constrain as we like.
I feel like swift has given up a lot of things just to make it easier for beginners to learn or maybe the language hasn't matured enough yet.
In Swift 3.1 you can add an extension to optional values as well:
extension Optional where Wrapped == String {
var isBlank: Bool {
return self?.isBlank ?? true
}
}
extension Optional where Wrapped == String {
var isNil: Bool {
return self == nil
}
}
The above answer written by @Vlad Hatko works fine, but in Swift 4 there are some issues so I changed it to this.
Extensions on Optional
that return a String
As of Swift 3, you cannot directly constrain an extension method to an optional String
. You can achieve the equivalent result with protocols as Daniel Shin's answer explains.
You can however, create an extension method on an Optional of any type and I've found some useful methods that have a String
return value. These extensions are helpful for logging values to the console. I've used asStringOrEmpty() on a String
optional when I want to replace a possible nil with empty string.
extension Optional {
func asStringOrEmpty() -> String {
switch self {
case .some(let value):
return String(describing: value)
case _:
return ""
}
}
func asStringOrNilText() -> String {
switch self {
case .some(let value):
return String(describing: value)
case _:
return "(nil)"
}
}
}
Example Use:
var booleanValue: Bool?
var stringValue: String?
var intValue: Int?
print("booleanValue: \(booleanValue.asStringOrNilText())")
print("stringValue: \(stringValue.asStringOrNilText())")
print("intValue: \(intValue.asStringOrNilText())")
booleanValue = true
stringValue = "text!"
intValue = 41
print("booleanValue: \(booleanValue.asStringOrNilText())")
print("stringValue: \(stringValue.asStringOrNilText())")
print("intValue: \(intValue.asStringOrNilText())")
Console Output:
booleanValue: (nil)
stringValue: (nil)
intValue: (nil)
booleanValue: true
stringValue: text!
intValue: 41
Optional
different than nil pointer
These extensions illustrate that an Optional
is different that a nil pointer. An Optional
is a enum
of a specified type (Wrapped
) which indicates that it does or does not contain a value. You can write an extension on the Optional
"container" even though it may not contain a value.
Excerpt from Swift Optional Declaration
enum Optional<Wrapped> : ExpressibleByNilLiteral {
/// The absence of a value.
case none
/// The presence of a value, stored as `Wrapped`.
case some(Wrapped)
...
}
In code, the absence of a value is typically written using the nil
literal rather than the explicit .none
enumeration case.