Introduction to swift optional values 4

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"
复制代码

おすすめ

転載: juejin.im/post/7088957710860353573