Swift where 条件检查 属性 是否实现
Swift where condition to check if a property is implemented
我刚刚在 Swift 中找到了另一种充分利用协议和协议扩展的方法,方法是扩展可选协议以添加一个函数,这样我就可以提供默认值。
我在这里写了一篇关于此的博客 post:https://janthielemann.de/random-stuff/providing-default-values-optional-string-empty-optional-string-swift-3-1/
post 的要点是,我需要一种简洁明了的方法来为可选字符串提供默认值,即 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 泛型实际上是不需要的,我创建了一个运算符,以便更快地访问和更方便地使用(至少我是这么认为的。随时纠正我,我总是乐于学习新事物并提高自己)。
我称它为 "not empty nil coalescing" 运算符(谁能想出更好的名字?我觉得我很不擅长命名 :/ )。希望有一天它能帮助某人:
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)
不,您不能在不使用协议的情况下查询对象或值是否具有特定的 属性 作为扩展的约束。这需要以一种目前未在 Swift 中实现的方式进行反思。此外,isEmpty
属性 对于不同的类型可能具有不同的含义,因此测试是否存在方法或 属性 而不是协议可能会导致意外行为。
你可以直接写
if let unwrappedString = optionalString, !unwrappedString.isEmpty {
// Do stuff
} else {
// Use default value
}
无需协议或扩展,可读性强。
在 Swift 4 中,它将在今年秋天推出,String
will conform to BidirectionalCollection
,它继承自 Collection
。 Collection
协议提供了一个 isEmpty
属性,所以你的扩展可以是
extension Optional where Wrapped: Collection {
// ...
}
但即便如此,您首先应该考虑在存储空字符串时将它们设置为 nil,因为您现在有两个状态(nil 和 empty),它们似乎代表完全相同的事物。
我刚刚在 Swift 中找到了另一种充分利用协议和协议扩展的方法,方法是扩展可选协议以添加一个函数,这样我就可以提供默认值。
我在这里写了一篇关于此的博客 post:https://janthielemann.de/random-stuff/providing-default-values-optional-string-empty-optional-string-swift-3-1/
post 的要点是,我需要一种简洁明了的方法来为可选字符串提供默认值,即 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
?
更新
正如 Paulo 所建议的那样,T 泛型实际上是不需要的,我创建了一个运算符,以便更快地访问和更方便地使用(至少我是这么认为的。随时纠正我,我总是乐于学习新事物并提高自己)。
我称它为 "not empty nil coalescing" 运算符(谁能想出更好的名字?我觉得我很不擅长命名 :/ )。希望有一天它能帮助某人:
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)
不,您不能在不使用协议的情况下查询对象或值是否具有特定的 属性 作为扩展的约束。这需要以一种目前未在 Swift 中实现的方式进行反思。此外,isEmpty
属性 对于不同的类型可能具有不同的含义,因此测试是否存在方法或 属性 而不是协议可能会导致意外行为。
你可以直接写
if let unwrappedString = optionalString, !unwrappedString.isEmpty {
// Do stuff
} else {
// Use default value
}
无需协议或扩展,可读性强。
在 Swift 4 中,它将在今年秋天推出,String
will conform to BidirectionalCollection
,它继承自 Collection
。 Collection
协议提供了一个 isEmpty
属性,所以你的扩展可以是
extension Optional where Wrapped: Collection {
// ...
}
但即便如此,您首先应该考虑在存储空字符串时将它们设置为 nil,因为您现在有两个状态(nil 和 empty),它们似乎代表完全相同的事物。