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
的参数保留为可选参数,那么您的原始代码实际上可以工作,但您需要更改在第二个示例中传递值的方式。
因为 T
是 String?
,你方法中的参数是 String??
类型并且传递 nil String??
与传递 [=20] 不同=] 恰好包含 nil
.
如果您将其命名为:
MyObject<String?>().start(.some(nil))
或
let string: String? = nil
MyObject<String?>().start(string)
然后它会打印"nil"
我有这段代码
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
的参数保留为可选参数,那么您的原始代码实际上可以工作,但您需要更改在第二个示例中传递值的方式。
因为 T
是 String?
,你方法中的参数是 String??
类型并且传递 nil String??
与传递 [=20] 不同=] 恰好包含 nil
.
如果您将其命名为:
MyObject<String?>().start(.some(nil))
或
let string: String? = nil
MyObject<String?>().start(string)
然后它会打印"nil"