Swift:为Optional值创建一个中缀运算符,在空时提供默认值

时间:2017-05-20 19:16:30

标签: ios swift operators extension-methods optional

关于我的上一个问题(在这里:Swift where condition to check if a property is implemented),我认为通过使用以下代码创建协议扩展以提供nil或空字符串的默认值非常聪明,我现在有了另一个问题。但首先,继承人的代码:

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 {}

如您所见,我现在可以为实现我定义的Emptyable协议的选项提供默认值。我这样做是为了保存这种风格的重复代码(更多关于为什么我在另一个问题中提到的博客文章中这样做):

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

现在为了学习并成为更好的开发人员,我认为创建一个新的运算符来为我调用orWhenNilOrEmpty函数会很有趣:

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

所以我尝试了这个:

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

但我得到了这个错误,我不明白为什么。我希望你能澄清这个问题并解释我做错了什么:

generic parameter 'Wrapped' could not be inferred

1 个答案:

答案 0 :(得分:0)

原来问题是试图在函数声明中使用泛型TDefaultPrecedence也不是最佳选择。这就是我现在解决它的方式以及它是如何工作的:

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)
    }
}

现在我所要做的就是在任何地方实现Emptyable然后我可以使用???从任何可选项中获取非空值:

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