84

你可以像这样创建一个字符串扩展:

extension String {
   func someFunc() -> Bool { return true }
}

但是如果你想让它应用于可选字符串呢?

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

尝试添加extension String? {会产生错误:

约束扩展必须在非特化泛型类型“可选”上声明,约束由“where”子句指定

4

9 回答 9

203

在 Swift 3.1 中,您还可以为可选值添加扩展:

extension Optional where Wrapped == String {
  var isBlank: Bool {
    return self?.isBlank ?? true
  }
}
于 2017-03-28T05:31:38.343 回答
13

你可以这样做:

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")

您无法限制OptionalString就此而言的原因是因为它们是struct. 通过为每个制定伪协议,现在我们可以随意进行约束。

我觉得 swift 放弃了很多东西,只是为了让初学者更容易学习,或者语言还不够成熟。

于 2015-11-15T08:40:58.833 回答
9

扩展Optional返回一个String

从 Swift 3 开始,您不能直接将扩展方法限制为可选的String. 正如 Daniel Shin 的回答所解释的那样,您可以使用协议获得等效的结果。

但是,您可以在任何类型的 Optional 上创建扩展方法,并且我发现了一些具有String返回值的有用方法。这些扩展有助于将值记录到控制台。String当我想用空字符串替换一个可能的 nil 时,我在一个可选项上使用了 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不同于零指针

这些扩展说明 anOptional与 nil 指针不同。AnOptionalenum指定类型 ( Wrapped) 的 a,表示它包含或不包含值。您可以在“容器”上编写扩展名,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枚举情况来编写的。

于 2017-01-23T19:30:19.650 回答
8
extension Optional where Wrapped == String {
    var isNil: Bool {
        return self == nil
    }
}

@Vlad Hatko 写的上述答案工作正常,但在 Swift 4 中存在一些问题,所以我将其更改为这个。

于 2018-02-11T21:35:36.990 回答
7

在 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
    }
}
于 2018-12-10T16:04:53.380 回答
3

从 Xcode 9.3 开始,您可以对@Vladyslav 的回答进行轻微修改:

extension Optional where Wrapped == String {

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

}
于 2018-05-24T09:24:36.907 回答
2

更新:有关适用于 Swift 2 及更高版本的解决方法,请参阅Daniel Shin 的回答


可选字符串本身不是类型,因此您不能在可选类型上创建扩展。在 Swift 中,anOptional只是一个枚举(加上一点语法糖),它可以是None,也可以是Some包装一个值。要使用您的 String 方法,您需要打开optionalString. 您可以轻松地使用可选链接来实现此目的:

optionalString?.someFunc()

如果optionalString不是nilsomeFunc将调用它。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(即truefalsenil)。所以doSomething()只会在optionalStringis not 并且该字符串为空时nil调用。

另一种选择是:

if let string = optionalString where string.isEmpty {
    doSomethingWithEmptyString(string)
}
于 2015-04-05T22:47:51.407 回答
1

发现了一些技巧 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});
于 2017-06-30T11:59:38.217 回答
1

您可以创建一个可选的字符串扩展。如果它是 nil ,我执行了以下操作以将可选字符串设置为空:

extension Optional where Wrapped == String {

    mutating func setToEmptyIfNil() {
        guard self != nil else {
            self = ""
            return
        }
    }

}
于 2020-01-03T06:45:16.303 回答