Swift条件来检查一个属性是否被实现 [英] Swift where condition to check if a property is implemented

查看:150
本文介绍了Swift条件来检查一个属性是否被实现的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我刚刚发现了另一种方法,通过扩展可选协议来添加一个函数,以便在Swift中充分利用协议和协议扩展,从而可以提供默认值。

我在这里写了一篇博客文章: https://janthielemann.de/random-stuff/providing-default-values-optional-string-empty-optional-string-swift -3-1 /



这篇文章的要点是我需要一个干净而简单的方法为可选String提供默认值,它们是nil或空。为此,我创建了一个可清空的协议端,扩展了可选协议,如下所示:

 协议可清空{
var isEmpty :Bool {获得}
}

扩展可选在哪里包装:可清空{
func orWhenNilOrEmpty< T:可清空>(_ defaultValue:T) - > T {
switch(self){
case .none:
return defaultValue
case .some(let value)where value.isEmpty:
return defaultValue
case .some(让值):
返回值为! T




扩展字符串:可清空{}

现在的问题是:有没有一种方法可以摆脱Emptyable协议,而是通过条件检查是否实现了属性或函数泛型类型,以便我为每个具有 isEmpty



的类型自动获取orWhenNilOrEmpty更新

正如Paulo所建议的那样,T泛型实际上并不需要,我创建了一个运算符,以便更快地访问和更方便的使用(至少我认为所以,随时纠正我,我总是乐于学习新事物,并提高自己)。



我把它称为不为空的无合并操作符(谁可以提出更好的名称?我觉得我吮吸命名的东西:/)。希望有一天它可以帮助某人:

 协议可清空{
var isEmpty:Bool {get}
}

中缀运算符???:NilCoalescingPrecedence

扩展可选在哪里包装:可清空{
func orWhenNilOrEmpty(_ defaultValue:Wrapped) - >包裹{
switch(self){
case .none:
return defaultValue
case .some(let value)where value.isEmpty:
return defaultValue
case .some(let value):
返回值
}
}

静态函数???(left:Wrapped?,right:Wrapped) - > ; Wrapped {
return left.orWhenNrOrEmpty(right)
}
}

扩展字符串:可清空{}

扩展数组:可清空{ }

extension MyStruct:Emptyable {
let text:String
let number:Int
var isEmpty:Bool {return text.isEmpty&&数字== 0}
init(text:String,number:Int){
self.text = text
self.number = number
}
}

让mandatoryNotEmptyString = optionalOrEmptyString ??? 默认值
让mandatoryNotEmptyStruct = optionalOrEmptyStruct ??? MyStruct(name:Hello World,number:1)


解决方案

不,您无法查询对象或值是否具有某个特定属性作为不使用协议的扩展的约束。这需要以目前尚未在Swift中实施的方式进行反思。此外, isEmpty 属性可能对不同类型有不同的含义,因此测试方法或属性的存在性而不是协议可能会导致意外的行为。



如果让unwrappedString = optionalString,!unwrappedString.isEmpty {

 
//做东西
} else {
//使用默认值
}

不需要任何协议或扩展,并且非常易读。

在今年秋季推出的Swift 4中, String 符合 BidirectionalCollection ,它继承自集合集合协议提供了一个 isEmpty 属性,所以你的扩展可以是

 扩展可选在哪里包装:集合{
// ...
}

但是即使如此,在将它们存储在第一位时,您应该考虑将空字符串设置为零,因为您现在有两种状态(零和空),它们似乎代表确切同样的事情。


I just found another way to make a great use of protocols and protocol extensions in Swift by extending the Optional protocol to add a function so I can provide default values.

I wrote a blog post about this here: https://janthielemann.de/random-stuff/providing-default-values-optional-string-empty-optional-string-swift-3-1/

The gist of the post is that I needed a clean and easy way to provide default values for optional String which are nil or empty. To do this, I created a Emptyable protocol end extended the Optional protocol like so:

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

Now the question is: Is there a way I can get rid of the Emptyable protocol and instead have a conditional check whether or not a property or function is implemented by the generic type so that I automatically get orWhenNilOrEmpty() for each and every type which has isEmpty?

UPDATE

As suggested by Paulo, the T generic is actually not needed and I created a operator for even quicker access and more convenient usage (at least I think so. Feel free to correct me, I'm always happy to learn new things and improve myself).

I call it the "not empty nil coalescing" operator (who can come up with a better names? I feel like I suck at naming things :/ ). Hopefully some day it helps somebody:

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)

解决方案

No, you cannot query if an object or value has a certain property as a constraint on an extension without using a protocol. That would require reflection in a way that is currently not implemented in Swift. Also, an isEmpty property could have different meanings for different types, so testing for the existence of a method or property instead of a protocol could lead to unexpected behaviour.

You could just write

if let unwrappedString = optionalString, !unwrappedString.isEmpty {
    // Do stuff
} else {
    // Use default value
}

No protocol or extension required and very readable.

In Swift 4, which is coming out this fall, String will conform to BidirectionalCollection, which inherits from Collection. The Collection protocol provides an isEmpty property, so your extension could be

extension Optional where Wrapped: Collection {
     // ...
}

But even then you should consider to set empty strings to nil when storing them in the first place, because you now have two states (nil and empty) which seem to represent the exact same thing.

这篇关于Swift条件来检查一个属性是否被实现的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆