【发布时间】:2017-05-20 16:44:33
【问题描述】:
我刚刚找到了另一种在 Swift 中充分利用协议和协议扩展的方法,方法是扩展 Optional 协议以添加一个函数,这样我就可以提供默认值。
我在这里写了一篇关于此的博客文章:https://janthielemann.de/random-stuff/providing-default-values-optional-string-empty-optional-string-swift-3-1/
这篇文章的要点是,我需要一种简洁的方法来为可选的 String 提供 nil 或空的默认值。为此,我创建了一个 Emptyable 协议,以扩展 Optional 协议,如下所示:
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 协议,而是有条件地检查属性或函数是否由泛型类型实现,以便我自动为每个具有 isEmpty 的类型获取 orWhenNilOrEmpty()?
更新
正如 Paulo 所建议的,实际上不需要 T 泛型,我创建了一个操作符以更快地访问和更方便地使用(至少我是这么认为的。请随时纠正我,我总是很乐意学习新事物并提高自己)。
我称之为“非空 nil 合并”运算符(谁能想出更好的名字?我觉得我在命名事物时很烂 :/ )。希望有一天它可以帮助某人:
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)
}
}
extension String: Emptyable {}
extension Array: Emptyable {}
extension MyStruct: Emptyable {
let text: String
let number: Int
var isEmpty: Bool { return text.isEmpty && number == 0 }
init(text: String, number: Int) {
self.text = text
self.number = number
}
}
let mandatoryNotEmptyString = optionalOrEmptyString ??? "Default Value"
let mandatoryNotEmptyStruct = optionalOrEmptyStruct ??? MyStruct(name: "Hello World", number: 1)
【问题讨论】:
-
你的
orWhenNilOrEmpty函数真的需要通用吗?你不能用Wrapped替换T吗?或者您的 API 是否旨在支持任意类型的默认值(但在最后一行,您的强制转换可能总是成功)? -
你是对的。 T 实际上根本不需要。感谢您的提示!
标签: swift generics protocols extension-methods