2017-05-20 3 views
2

オプションプロトコルを拡張してデフォルト値を提供できるようにするために、Swiftでプロトコルとプロトコル拡張を使い分ける別の方法が見つかりました。スウィフトここでプロパティが実装されているかどうかを確認する条件

私はここでこのことについてブログ記事を書いた:https://janthielemann.de/random-stuff/providing-default-values-optional-string-empty-optional-string-swift-3-1/

をポストの要旨は、私がnilまたは空になっているオプションの文字列にデフォルト値を提供するために、クリーンで簡単な方法を必要としていることです。これを行うために、私はEmptyableプロトコルエンドがそうのようなオプションのプロトコル拡張作成:

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の各型ごとにorNhenOrEmpty()が自動的に取得されます。

UPDATE

パウロによって示唆されるように、Tジェネリックが実際に必要と私は(少なくとも私はそう思うでもすばやくアクセスし、より便利な使用のための演算子を作成されません。私を修正すること自由に感じ、I新しいことを学び、自分自身を改善することはいつでもうれしい)。

私はそれを "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) 
+0

'orWhenNilOrEmpty'関数は本当に汎用である必要がありますか? 'T'を' Wrapped'で置き換えることはできませんか?あるいは、あなたのAPIが任意にタイプされたデフォルト値をサポートするように設計されていますか? –

+0

あなたは正しいです。 Tは実際にはまったく必要ありません。ヒントありがとう! – xxtesaxx

答えて

1

ないオブジェクトや値はプロトコルを使用せずに延長上の制約などの特定の性質を持っている場合は、照会することはできません。それは、Swiftで現在実装されていない方法で反映する必要があります。また、isEmptyプロパティは、異なる種類の異なる意味を持つ可能性があるため、プロトコルではなくメソッドまたはプロパティの存在をテストすると、予期しない動作が発生する可能性があります。

あなただけ

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

ないプロトコルや必要な拡張機能と非常に読みやすい書くことができます。

今秋に出てくるスウィフト4ではString will conform to BidirectionalCollectionで、Collectionから継承しています。あなたの拡張機能は、

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

しかし、たとえ、あなたが最初の場所でそれらを格納するときにnilに空の文字列を設定するために検討すべきかもしれないので、Collectionプロトコルは、isEmptyプロパティを提供し、あなたは今、二つの状態(ゼロと空を持っているので、 )これはまったく同じことを表すようです。

+0

ミラーを拡張の制約として使用することはできません。また、ラップされた型に関係なく、すべてのオプション値に対してメソッドを提供することは本当に悪いことです。 – Palle

+0

もちろん、あなたは正しいです!とにかく、ありがとう;) –

+2

"let x = y、!x.isEmpty ..."はまさに私が取り除きたいものでした。:)とにかく、私はすでに、機能やプロパティの存在を確認することができないと考えていたので、確認のおかげで。ちなみに、私はもう一歩進んで、私の機能を???という演算子にしました。たぶん少し上ですが、それは実際のクライアントプロジェクトで使用するよりも、私にとって学びやすいことです。さて、私の個人的なプロジェクトでは、おそらくそれを利用します:D – xxtesaxx

関連する問題