swift 可选泛型和嵌套可选展开

swift optional generic type and nested optional unwrapping

我有这段代码

class MyObject<T> {

    func start(_ value: T?) {
        if let value = value {
            doSomething(value)
        }
    }

    func doSomething(_ value: T) {
        print(value)
    }
}

MyObject<String>().start("some")
// prints "some"

MyObject<String?>().start(nil)
// doesn't print anything

我需要为每个传递给 start() 的有效值调用 doSomething()。当 T 已经是可选类型时 String?,那么 nil 是一个有效值。

是否需要在 MyObject 的扩展中编写两个版本的 start(),并在 T 的类型上添加条件?以及如何去做?

由于 let value = value 在第二个输入中失败,您需要单独处理该情况。

func start(_ value: T?) {
    if let value = value {
        doSomething(value)
    }
    else
    {
        print("nil input")
    }
}

如果值为 nil,当您解包时,该值将不会进入 if 语句。相反,您可以这样做:

class MyObject<T> {

    func start(_ value: T?) {
        if let value = value {
            doSomething(value)
        } else {
            print("nil")
        }
    }

    func doSomething(_ value: T) {
        print(value)
    }
}

Swift 中的可选只是一个有两种情况的通用枚举:

enum Optional<T> {
    case some(T)
    case none
}

例如 String?Optional<String> 相同。

如果你声明 MyObject<String?> 基本上你就是在创建这个 MyObject<Optional<String>>,所以你的具体 start 方法将是

func start(_ value: Optional<Optional<String>>) { ... }

这意味着如果你像start(nil)那样调用它,整个对象当然会是nil而if let会失败。 但是,您可以通过这种方式调用该函数

MyObject<String?>().start(Optional.some(Optional.none))
MyObject<String?>().start(.some(.none)) // -> shorter version with type inference

基本上现在外部可选存在并且展开工作,但内部是 nil

但是我还是不明白为什么你需要做那样的事情

您可以让 start 函数采用 non-optional T 并且总是调用 doSomething 而不是先尝试解包。如果 T 本身是可选类型,这将只允许您调用 start(nil)

class MyObject<T> {

    func start(_ value: T) {
        doSomething(value)
    }

    func doSomething(_ value: T) {
        print(value)
    }
}

MyObject<String>().start("some")
// prints "some"

MyObject<String?>().start(nil)
// prints "nil"

如果您想将 start 的参数保留为可选参数,那么您的原始代码实际上可以工作,但您需要更改在第二个示例中传递值的方式。

因为 TString?,你方法中的参数是 String?? 类型并且传递 nil String?? 与传递 [=20] 不同=] 恰好包含 nil.

如果您将其命名为:

MyObject<String?>().start(.some(nil))

let string: String? = nil
MyObject<String?>().start(string)

然后它会打印"nil"