Swift 如何添加可选的字符串扩展名?

Swift 如何添加可选的字符串扩展名?,swift,swift-extensions,Swift,Swift Extensions,您可以创建如下所示的字符串扩展名: extension String { func someFunc() -> Bool { return true } } 但如果您希望它应用于可选字符串,该怎么办 var optionalString: String? = "" optionalString!.someFunc() /* String? does not have a member someFunc */ 是否正在尝试添加扩展字符串?{产生错误: 必须在非专

您可以创建如下所示的字符串扩展名:

extension String {
   func someFunc() -> Bool { return true }
}
但如果您希望它应用于可选字符串,该怎么办

var optionalString: String? = ""
optionalString!.someFunc() /* String? does not have a member someFunc */
是否正在尝试添加
扩展字符串?{
产生错误:

必须在非专用泛型类型“Optional”上声明受约束的扩展,并使用“where”子句指定的约束


更新:有关适用于Swift 2及以上版本的解决方案,请参阅


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

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

您可以这样做:

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
  }
}
以及:

您不能约束
可选
字符串
,因为它们是
struct
。通过为每一个都创建伪协议,现在我们可以随意约束

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

可选
的扩展返回
字符串
从Swift 3开始,您不能直接将扩展方法约束到可选的
字符串
。如Daniel Shin的回答所述,您可以通过协议获得相同的结果

但是,您可以在任何类型的可选项上创建扩展方法,我发现一些有用的方法具有
字符串
返回值。这些扩展有助于将值记录到控制台。当我想用空字符串替换可能的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
控制台输出:

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

可选
不同于零指针 这些扩展说明
可选的
不同于零指针。
可选的
是指定类型(
包装的
)的
枚举
,表示它包含或不包含值。您可以在
可选的
容器上编写扩展即使它可能不包含值

Swift可选声明摘录

enum Optional<Wrapped> : ExpressibleByNilLiteral {

    /// The absence of a value.
    case none

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

    ...
}
enum可选:expressiblebynellateral{
///缺少一个值。
无案例
///值的存在,存储为“Wrapped”。
包装箱(已包装)
...
}

在代码中,缺少值通常使用
nil
文本而不是显式
.none
枚举情况写入。

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

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

找到了一些技巧,斯威夫特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});
A类{
变量名称:String!;
init(uu名称:String?){
self.name=名称;
}
}
扩展名可选,其中Wrapped==String{
func compareText(uu其他:字符串?)->Bool{
开关(自身、其他){
案例(a?、b?):
返回a

以上由@Vlad Hatko编写的答案很好,但在Swift 4中存在一些问题,因此我将其改为此。

自Xcode 9.3以来,您可以使用@Vladyslav的答案的这一细微修改:

extension Optional where Wrapped == String {

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

}

在Swift 4.1中,我遇到了一个
可选的不明确的生成错误,用于此上下文中的类型查找
生成错误。要修复此错误,必须将Swift命名空间显式添加到类型:

extension Swift.可选,其中Wrapped==String{
var为空:Bool{
返回自我?为空?为真
}
}

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

extension Optional where Wrapped == String {

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

}

您需要始终将其展开才能应用扩展。所以我将其展开,但可能是我做错了?
optionalString!.someFunc()
如果您确定optional不会返回nil,那没关系,否则您需要使用If-letIt有时会为nil,这就是为什么使用optional。我仍在调试,我怀疑我的游乐场是不同步的。我可能会马上结束这个问题。@LeonardoSavioDabus是的,这就是我希望在扩展中添加并使用扩展t的原因o solve。我不喜欢嵌套的IF语句。我猜Swift的未来版本最终会在这方面有所改进。我试图创建一个扩展以避免可选绑定。似乎不会possible@vol7ron请问为什么?可选的链接/绑定不方便吗?考虑一个你想检查的可选字符串据我所知,您必须使用嵌套的if's
if let str=optString{if str.isEmpty{doSomething();}}
我宁愿这是一个
isBlank
扩展名