简体   繁体   English

swift 可选的泛型类型和嵌套的可选解包

[英]swift optional generic type and nested optional unwrapping

I've got this piece of code我有这段代码

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

I need doSomething() to be called for every valid value passed to start() .我需要为传递给start()每个有效值调用doSomething() start() And when T is already an optional type like String?T已经是像String?这样的可选类型时String? , then nil is a valid value. ,则nil是有效值。

Do I need to write two versions of start() in extensions of MyObject with conditions on the type of T ?我是否需要在MyObject扩展中编写两个版本的start()并带有T类型的条件? And how to do it?以及怎么做?

You can make your start function take a non-optional T and just always call doSomething instead of trying to unwrap it first.你可以让你的start函数接受一个非可选的T并且总是调用doSomething而不是首先尝试解包它。 This would only allow you to call start(nil) if T itself was an optional type:如果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"

If you want to leave the parameter to start as optional then your original code will actually work, but you need to change the way you are passing your value in your second example.如果你想离开参数来start可选那么你原来的代码将实际工作,但你需要改变你传递你的价值在你的第二个例子的方式。

Since T is String?由于TString? , the parameter in your method is of type String?? , 你方法中的参数是String?? and passing a nil String??并传递一个零String?? is different then passing one with a String?与传递一个String? that happens to contain nil .恰好包含nil

If you call it as:如果你称之为:

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

or或者

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

Then it will print "nil"然后它会打印“nil”

Since let value = value fails with the second input you need to handle that case separately.由于 let value = value 在第二个输入时失败,您需要单独处理这种情况。

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

In case value is nil, when you unwrap the value will not enter in the if statement.如果值为 nil,则解包时该值将不会进入 if 语句。 Instead, you can do this:相反,您可以这样做:

class MyObject<T> {

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

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

Optional in Swift is just a generic enum that have two cases: Swift 中的 Optional 只是一个通用枚举,它有两种情况:

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

For example String?例如String? is the same thing of Optional<String> .Optional<String>

If you declare MyObject<String?> basically you're creating this MyObject<Optional<String>> , so your concrete start method will be如果你声明MyObject<String?>基本上你正在创建这个MyObject<Optional<String>> ,所以你的具体start方法将是

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

This means that if you call it like start(nil) , the whole object will be of course nil and the if let will fail.这意味着如果你像start(nil)一样调用它,整个对象当然会是 nil 并且if let会失败。 You can however call that function in this way但是,您可以通过这种方式调用该函数

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

Basically now the outer optional exists and the unwrap works, but the inner one is nil .基本上现在外部的 optional 存在并且 unwrap 工作,但内部的是nil

However I still can't understand why would you need to do something like that但是我仍然不明白为什么你需要做这样的事情

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM