我想简化常量需要做的事情
if let firstName = firstName {
self.name = firstName
}
执行此操作的可能的自定义通用运算符是
infix operator ?= {}
func ?= <T>(inout left: T, right: T?) {
if let right = right {
left = right
}
}
将前面的示例简化为
self.name ?= firstName
这会产生一个问题,如果 firstName 的值为 nil,那么 Swift 会将该值包装在可选值中。
var name: String? = "Bob"
var firstName: String? = nil
self.name ?= firstName
print(self.name)
/*
prints "nil" since it is wrapping firstName in an optional when
passed in.
E.g. Optional<nil> gets unwrapped to nil in function and assigned
*/
对自定义运算符有任何可能的修复吗?我尝试将左侧参数限制为不是可选参数,但这对于泛型的类型约束是不可能的。
最佳答案
问题(正如您已正确识别的那样)是因为左侧参数的类型为 T
,当您将可选值传递给它时 T
将被推断为 Optional<Whatever>
。因为右侧参数是 T?
(并且因为类型可以自由提升为可选类型),它将推断类型为 Optional<Optional<Whatever>>
,导致您观察到令人困惑的双重包装。
解决方案是添加一个重载来处理左侧参数也是可选的情况。
infix operator ?= {}
func ?= <T>(inout left: T, right: T?) {
if let right = right {
left = right
}
}
// overload to deal with an optional left handed side
func ?= <T>(inout left: T?, right: T?) {
if let right = right {
left = right
}
}
(请注意,在 Swift 3 中,inout
应出现在参数类型之前)
现在,如果您使用带有可选值的此运算符作为左手参数,Swift 将使用重载版本而不是原始版本,因为它始终倾向于更特定于类型的签名。这意味着右侧不会被包裹在双可选中,因为它现在与左侧参数的类型完全相同。
var name: String? = "Bob"
var firstName: String? = nil
name ?= firstName
print(name) // prints: Optional("Bob")
请注意,这与 ??
类似。确实如此,它有两个定义来处理一侧是可选的、一侧是非可选的以及两侧都是可选的,以避免生成双重包装的选项:
@warn_unused_result
public func ??<T>(optional: T?, @autoclosure defaultValue: () throws -> T) rethrows -> T
@warn_unused_result
public func ??<T>(optional: T?, @autoclosure defaultValue: () throws -> T?) rethrows -> T?
关于ios - 自定义运算符来简化 If-Let,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/37866087/