次のようなString拡張機能を作成できます。
extension String {
func someFunc -> Bool { ... }
}
しかし、オプションの文字列に適用する場合はどうでしょうか?
var optionalString :String? = ""
optionalString!.someFunc() /* String? does not have a member someFunc */
Swift 3.1では、オプションの値に拡張子を追加することもできます。
extension Optional where Wrapped == String {
var isBlank: Bool {
return self?.isBlank ?? true
}
}
次のようにできます:
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はそれを作るために多くのことをあきらめた簡単初心者が学ぶためか、言語がまだ十分に成熟していないようだ。
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
リテラルを使用して記述されます。
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
}
}
extension Optional where Wrapped == String {
var isNil: Bool {
return self == nil
}
上記の回答(@Vlad Hatkoによって書かれた)は正常に動作しますが、Swift 4ではいくつかの問題があるため、これに変更しました。
更新:Swift 2以上で動作する回避策については、 Daniel Shin's answer =
オプションの文字列はそれ自体が型ではないため、オプションの型に拡張機能を作成することはできません。 Swiftでは、Optional
は単なる列挙型(および少しの構文糖)であり、None
、または値をラップするSome
のいずれかです。 Stringメソッドを使用するには、optionalString
をアンラップする必要があります。オプションの連鎖を簡単に使用して、これを実現できます。
_optionalString?.someFunc()
_
optionalString
がnil
でない場合、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(つまり、true
、false
、またはnil
)を返すために機能します。したがって、doSomething()
は、optionalString
がnotnil
、andその文字列が空の場合。
別の選択肢は次のとおりです。
_if let string = optionalString where string.isEmpty {
doSomethingWithEmptyString(string)
}
_
Xcode 9.3以降、@ Vladyslavの答えのこのわずかな変更を使用できます。
extension Optional where Wrapped == String {
var isEmpty: Bool {
return self?.isEmpty ?? true
}
}
いくつかのトリックを見つけました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});