2016-05-25 31 views
5

我想简化需要不断做运营商定制,简化如果-让

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 

这会产生一个问题,如果名字的值是,那么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 
*/ 

任何可能的修复自定义运算符?我试图限制左边的参数不是可选的,但这对于泛型的类型约束是不可能的。

回答

10

问题(因为您已经正确识别)是因为左侧参数类型为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 
    } 
} 

(注意,在斯威夫特3,inout应的参数类型之前出现的),如果你使用这个操作符与可选的左手参数

现在,斯威夫特将使用重载的版本,而不是原始版本,因为它会始终支持更多类型特定的签名。这意味着右侧不会被包含在double可选项中,因为它现在与左侧参数的类型完全相同。

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? 
+2

这很酷 – marchinram

0

我发现了一个有趣的方式通过无聚结,以减少if let开销操作

零合并运算符(a ?? b)如果 包含一个值,则展开可选的a;如果a为零,则返回默认值b。表达式a始终是可选类型。表达式b必须 与存储在a中的类型匹配。

总之 - nonOptional = optional ?? someDefaultValue
例如 -

let defaultColorName = "red" 
var userDefinedColorName: String? // optional variable 

var colorNameToUse = userDefinedColorName ?? defaultColorName 

所以,在这里,如果userDefinedColorName是零,然后defaultColorName将得到assighed非可选变量colorNameToUse
如需查看完整参考,请点击这里Swift documentation