web-dev-qa-db-ja.com

オプションの文字列拡張子を追加する方法は?

次のようなString拡張機能を作成できます。

extension String {
   func someFunc -> Bool { ... }
}

しかし、オプションの文字列に適用する場合はどうでしょうか?

var optionalString :String? = ""
optionalString!.someFunc() /* String? does not have a member someFunc */
57
vol7ron

Swift 3.1では、オプションの値に拡張子を追加することもできます。

extension Optional where Wrapped == String {
  var isBlank: Bool {
    return self?.isBlank ?? true
  }
}
147

次のようにできます:

protocol OptionalType { typealias A; var opt: A? { get } }
extension Optional: OptionalType { var opt: A? { return self } }

protocol StringType { var get: String { get } }
extension String: StringType { var get: String { return self } }

extension Optional where Wrapped: StringType {
  func getOrElse(s: String) -> String {
    return self.opt?.get ?? s
  }
}

そして:

let optStr: String? = nil
optStr.getOrElse("hello world")

OptionalまたはStringを制約できない理由は、それらがstructであるためです。それぞれに擬似プロトコルを作成することにより、今では好きなように制約できます。

Swiftはそれを作るために多くのことをあきらめた簡単初心者が学ぶためか、言​​語がまだ十分に成熟していないようだ。

12
Daniel Shin

Optionalを返すStringの拡張機能

Swift 3の時点で、オプションのStringに拡張メソッドを直接制約することはできません。DanielShinの答えが説明するように、プロトコルで同等の結果を達成できます。

ただし、任意の型のOptionalに拡張メソッドを作成できます。String戻り値を持つ便利なメソッドがいくつか見つかりました。これらの拡張機能は、コンソールに値を記録するのに役立ちます。可能性のあるnilを空の文字列で置き換える場合、オプションのStringでasStringOrEmpty()を使用しました。

extension Optional {
    func asStringOrEmpty() -> String {
        switch self {
            case .some(let value):
                return String(describing: value)
            case _:
                return ""
        }
    }

    func asStringOrNilText() -> String {
        switch self {
            case .some(let value):
                return String(describing: value)
            case _:
                return "(nil)"
        }
    }
}

使用例:

var booleanValue: Bool?
var stringValue: String?
var intValue: Int?

print("booleanValue: \(booleanValue.asStringOrNilText())")
print("stringValue: \(stringValue.asStringOrNilText())")
print("intValue: \(intValue.asStringOrNilText())")

booleanValue = true
stringValue = "text!"
intValue = 41

print("booleanValue: \(booleanValue.asStringOrNilText())")
print("stringValue: \(stringValue.asStringOrNilText())")
print("intValue: \(intValue.asStringOrNilText())")

コンソール出力:

booleanValue: (nil)
stringValue: (nil)
intValue: (nil)

booleanValue: true
stringValue: text!
intValue: 41

Optionalはnilポインターとは異なります

これらの拡張機能は、Optionalがnilポインターと異なることを示しています。 Optionalは、指定されたタイプ(enum)のWrappedであり、値が含まれているか含まれていないことを示します。値が含まれていない場合でも、Optional "コンテナ"に拡張機能を記述できます。

Swiftオプションの宣言からの抜粋)

enum Optional<Wrapped> : ExpressibleByNilLiteral {

    /// The absence of a value.
    case none

    /// The presence of a value, stored as `Wrapped`.
    case some(Wrapped)

    ...
}

コードでは、値の欠如は通常、明示的な.none列挙のケースではなく、nilリテラルを使用して記述されます。

7
Mobile Dan

Swift 4.1ではOptional is ambiguous for type lookup in this contextビルドエラー。修正するには、タイプにSwift名前空間を明示的に追加する必要があります。

extension Swift.Optional where Wrapped == String {
    var isBlank: Bool {
        return self?.isBlank ?? true
    }
}
3
caukajun
extension Optional where Wrapped == String {
var isNil: Bool {
    return self == nil
}

上記の回答(@Vlad Hatkoによって書かれた)は正常に動作しますが、Swift 4ではいくつかの問題があるため、これに変更しました。

3
dheeru

更新:Swift 2以上で動作する回避策については、 Daniel Shin's answer =


オプションの文字列はそれ自体が型ではないため、オプションの型に拡張機能を作成することはできません。 Swiftでは、Optionalは単なる列挙型(および少しの構文糖)であり、None、または値をラップするSomeのいずれかです。 Stringメソッドを使用するには、optionalStringをアンラップする必要があります。オプションの連鎖を簡単に使用して、これを実現できます。

_optionalString?.someFunc()
_

optionalStringnilでない場合、someFuncが呼び出されます。これを行う別の(簡潔ではない)方法は、オプションのバインディングを使用して、メソッドを呼び出す前にoptionalStringに値があるかどうかを確立することです。

_if let string = optionalString {
    string.someFunc()    // `string` is now of type `String` (not `String?`)
}
_

以下のコメントの例では、複数のifステートメントをネストする必要はありません。オプションの文字列が単一のifの空の文字列であるかどうかを確認できます。

_if optionalString?.isEmpty == true {
    doSomething()
}
_

これは、式_optionalString?.isEmpty_がオプションのBool(つまり、truefalse、またはnil)を返すために機能します。したがって、doSomething()は、optionalStringnotnilandその文字列が空の場合。

別の選択肢は次のとおりです。

_if let string = optionalString where string.isEmpty {
    doSomethingWithEmptyString(string)
}
_
2
Stuart

Xcode 9.3以降、@ Vladyslavの答えのこのわずかな変更を使用できます。

extension Optional where Wrapped == String {

    var isEmpty: Bool {
        return self?.isEmpty ?? true
    }

}
2
zero3nna

いくつかのトリックを見つけましたSwift 3

class A{
    var name:String!;
    init(_ name:String?){
        self.name = name;
    }
}

extension Optional where Wrapped == String {
    func compareText(_ other:String?)->Bool{
        switch (self,other){
        case let(a?,b?):
            return a < b;
        case (nil,_):
            return true;
        default:
            return false;
        }
    }
}

let words:[A] = [A("a"),A(nil),A("b"),A("c"),A(nil)];

// let sorted = words.sorted{ 0.name.compareText($1.name) }
// trick
let sorted = words.sorted{ ($0.name as String?).compareText($1.name) }

print(sorted.map{$0.name});
1
john07