Подтвердить что ты не робот

Как добавить необязательное расширение строки?

Вы можете создать расширение строки так:

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

но что, если вы хотите, чтобы оно применимо к необязательной строке?

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

Ответ 1

В Swift 3.1 вы также можете добавить расширение к необязательным значениям:

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

Ответ 2

Вы можете сделать это следующим образом:

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. Сделав псевдопротокол для каждого, теперь мы можем сдерживать, как нам нравится.

Я чувствую, что быстро отбросил множество вещей, чтобы сделать его проще для начинающих, чтобы узнать, или, может быть, язык еще недостаточно созрел.

Ответ 3

Расширения на Optional, которые возвращают String

С Swift 3 вы не можете напрямую ограничивать метод расширения необязательным String. Вы можете получить эквивалентный результат с протоколами, как объясняет ответ Даниэля Шин.

Однако вы можете создать метод расширения для необязательного типа любого типа, и я нашел несколько полезных методов, которые имеют возвращаемое значение String. Эти расширения полезны для записи значений на консоль. Я использовал asStringOrEmpty() на String необязательный, когда я хочу заменить возможное ноль пустой строкой.

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)

    ...
}

В коде отсутствие значения обычно записывается с использованием литерала nil, а не явного события перечисления .none.

Ответ 4

Обновление:. Обходной путь, который работает с Swift 2 и выше, см. Даниэль Шинс.


Необязательный String сам по себе не является типом, и поэтому вы не можете создать расширение для необязательного типа. В Swift a 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 не nil, и если эта строка пуста.

Другой вариант:

if let string = optionalString where string.isEmpty {
    doSomethingWithEmptyString(string)
}

Ответ 5

extension Optional where Wrapped == String {
var isNil: Bool {
    return self == nil
}

Приведенный выше ответ (написанный @Vlad Hatko) работает нормально, но в swift 4 есть некоторые проблемы, поэтому я изменил его на этот.

Ответ 6

нашел трюк 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});

Ответ 7

Начиная с Xcode 9.3, вы можете использовать эту небольшую модификацию ответа @Vladyslav:

extension Optional where Wrapped == String {

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

}

Ответ 8

В Swift 4.1 я получал Optional is ambiguous for type lookup in this context ошибке сборки Optional is ambiguous for type lookup in this context. Чтобы исправить, вы должны явно добавить пространство имен Swift к типу:

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