Get into the habit of writing together! This is the 19th day of my participation in the "Nuggets Daily New Plan · April Update Challenge", click to view the details of the event .
Optional value equality
let regex = "123"
if regex.first == "1" {}
复制代码
The above code can be run based on two points, the Wrapped type implements the Equatable protocol, and the Optional will implement the Equatable protocol
extension Optional: Equatable where Wrapped: Equatable {
static func ==(lhs: Wrapped?, rhs: Wrapped?) -> Bool {
switch (lhs, rhs) {
case (nil, nil): return true
case let(x?, y?): return x == y
case (nil, _?), (_?, nil): return false
}
}
}
复制代码
We don't necessarily need to write code like this
if regex.first == Optional("1") {}
复制代码
When we use a non-optional value, if we need to match it to an optional value type, Swift will always "upgrade" it to an optional value type
Without this implicit conversion, you need to implement three separate versions
// 两者都可选
func == <T: Equatable>(lhs: T?, rhs: T?) -> Bool
// lhs 非可选
func == <T: Equatable>(lhs: T, rhs: T?) -> Bool
// rhs 非可选
func == <T: Equatable>(lhs: T?, rhs: T) -> Bool
复制代码
Actually, we only need the first version. Many times rely on this implicit conversion, such as optional map, we convert the internal value and return it. However, the return value of our map is actually an optional value, and the compiler automatically completes the conversion for us, we do not need to write code such as return Optional(transform(value)). In the dictionary, because the key may not exist, the return value is an optional value. If there is no implicit conversion, we need to write the code myDict["key"] = Optional(someValue)
If you want to assign a value of nil to the dictionary
var dictWithNils: [String: Int?] = ["one": 1,
"two": 2,
"three": nil]
复制代码
dictWithNils["two"] = nil will remove the key
The following can be done
dictWithNils["two"] = .some(nil)
dictWithNils["two"] = Optional(nil)
dictWithNils["two"]? = nil
复制代码
The third method uses the optional chain method to set the value after successful acquisition
No value is updated or inserted for non-existent values
dictWithNils["four"]? = nil
print(dictWithNils) // ["one": Optional(1), "two": Optional(2), "three": nil]
复制代码
When to force unpack
Use an exclamation mark when you are sure that a value cannot be nil, you should hope that if it is !, the program should simply hang
extension Sequence {
func alt_commpactMap<T>(_ transform: (Element) -> T?) -> [T] {
return lazy.map(transform).filter { $0 != nil }.map { $0! }
}
}
复制代码
Here filter has filtered out nil, so map is used! There is no problem at all
Improve error message for forced unpacking
infix operator !!
func !!<T>(wrapped: T?, failtureText:@autoclosure () -> String) -> T {
if let x = wrapped { return x }
fatalError(failtureText())
}
复制代码
let s = "foo"
let i = Int(s) !! "Expecting integer, got"(s)""
复制代码
Use assertions in debug builds
Use assert when making assertions, the release version will be replaced with the default value
infix operator !?
func !?<T: ExpressibleByNilLiteral>(wrapped: T?, failureText: @autoclosure () -> String) -> T {
assert(wrapped != nil, failureText())
return wrapped ?? 0
}
复制代码
If you need to provide an explicit default value, you can define a parameter that accepts a tuple containing the default value and error message
infix operator !?
func !?<T: ExpressibleByNilLiteral>(wrapped: T?, nilDefault: @autoclosure () -> (value: T, text: String)) -> T {
assert(wrapped != nil, nilDefault().text)
return wrapped ?? nilDefault().value
}
复制代码
// 调试版本中断言,发布版本中返回 5
Int(s) !? (5, "Expected integer")
复制代码
For a function that returns Void, calling with optional chaining returns Void? , a non-generic version can be written to detect when an optional chaining call encounters nil and no operation
infix operator !?
func !?(wrapped: ()?, failureText: @autoclosure () -> String) {
assert(wrapped != nil, failureText())
}
复制代码
var output: String? = nil
output?.write("something") !? "wasn't expecting chained nil here"
复制代码