自定义运算符简化If-Let

时间:2016-05-25 16:12:34

标签: ios swift generics

我想简化一直需要做的事情

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
*/

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

2 个答案:

答案 0 :(得分:11)

问题(正如您已经正确识别的那样)是因为左侧参数的类型为 If Not trange.Value Is Nothing Then If .Cells(6, trange.Value).Value = "BOL" Then 'set first address Set fr = .Range(trange.Address) Do 'result counter c = c + 1 'save each address within cache range For Each i In addr If i.Value = "" Then i.Value = trange.Address Next i Set trange = trange.FindNext(trange) Loop While trange.Address <> fr.Address End IF End If ,当您将可选项传递给它时T将被推断为{{1} }}。因为右侧参数是T(因为类型可以自由地提升为选项),它会将类型推断为Optional<Whatever>,从而导致您正在观察的令人困惑的双重包装。

解决方案是添加一个重载来处理左侧参数也是可选的情况。

T?

(请注意,在Swift 3中,Optional<Optional<Whatever>>应出现在参数类型之前)

现在,如果你使用带有可选作为左手参数的this运算符,Swift将使用重载版本而不是原始版本,因为它总是支持更多类型特定的签名。这意味着右侧不会被双重选项包裹,因为它现在与左侧参数的类型完全相同。

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
    }
}

请注意,这类似于inout所做的,它有两个定义来处理一方是可选的,一方是非可选的&amp;双方都是可选的,以避免产生双重包裹的选项:

var name: String? = "Bob"
var firstName: String? = nil

name ?= firstName

print(name) // prints: Optional("Bob")

答案 1 :(得分:1)

我发现了一种通过 Nil Coalescing Operator 来减少if let开销的有趣方法

  

nil合并算子(a ?? b)打开一个可选的a if   包含一个值,如果a为nil,则返回默认值b。该   表达式a始终是可选类型。表达式b必须   匹配存储在。

中的类型

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

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

var colorNameToUse = userDefinedColorName ?? defaultColorName

因此,如果userDefinedColorName为零,那么defaultColorName将被分配给非可选变量colorNameToUse
有关完整参考,请查看此Swift documentation