简体   繁体   中英

Swift: create a infix operator for Optional values which provide default values when empty

In relation to my last question (over here: Swift where condition to check if a property is implemented ) where I thought I was very clever by creating a protocol extension to provide a default value for nil or empty strings by using the following code, I now have another question. But first, heres the code:

protocol Emptyable {
    var isEmpty: Bool { get }
}

extension Optional where Wrapped: Emptyable {
    func orWhenNilOrEmpty<T: Emptyable>(_ defaultValue: T) -> T {
        switch(self) {
        case .none:
            return defaultValue
        case .some(let value) where value.isEmpty:
            return defaultValue
        case .some(let value):
            return value as! T
        }
    }
}

extension String: Emptyable {}

As you see i can now provide default values for optionals implementing the Emptyable protocol I defined. I did this to save the ever repeating code of this style (more about why I do this in the blog post mentioned in the other question):

if let unwrapped = optional, !unwrapped.isEmpty {
    myLabel.text = unwrapped
} else {
    myLabel.text = "Some Default Text"
}

Now for the purpose of learning and becoming a better developer, I thought it could be fun to create a new operator to call the orWhenNilOrEmpty function for me like so:

let optionalString: String? = nil
let actualString: String = some ??? "Hello World"

So I tried this:

infix operator ???: DefaultPrecedence
extension Optional where Wrapped: Emptyable {
    static func ???<T>(left: T?, right: T) -> T {
        return left.orWhenNilAndEmpty(right)
    }
}

But I get this error and I don't really understand why. I hope you can clarify the issue and explain what I'm doing wrong:

generic parameter 'Wrapped' could not be inferred

Turns out the problem was trying to use a generic T in the function declaration. Also DefaultPrecedence wasn't the best choice. This is how I now solved it and how it works:

protocol Emptyable { var isEmpty: Bool { get } }

infix operator ???: NilCoalescingPrecedence

extension Optional where Wrapped: Emptyable {
    func orWhenNilOrEmpty(_ defaultValue: Wrapped) -> Wrapped {
        switch(self) {
        case .none:
            return defaultValue
        case .some(let value) where value.isEmpty:
            return defaultValue
        case .some(let value):
            return value
        }
    }

    static func ???(left: Wrapped?, right: Wrapped) -> Wrapped {
        return left.orWhenNilOrEmpty(right)
    }
}

Now all I have to do is implement Emptyable where ever I want and then I can use ??? to get a not empty value from any optional:

extension String: Emptyable {}
let notEmptyString = nilOrEmptyOptionalString ??? "Meaningful default value"

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM