自定义运算符来简化If-Let [英] Custom operator to simplify If-Let

查看:133
本文介绍了自定义运算符来简化If-Let的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我想简化不断需要做的事情

  if let firstName = firstName {
self.name = firstName

一个可能的自定义泛型操作符是

  infix operator?= {} 
func?=< T>(inout left:T,right:T?){
if right right = right {
left = right
}
}

将前面的示例简化为

  self.name?= firstName 

这会产生一个问题,如果 firstName 的值为 nil ,那么Swift将包装在可选的值。

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

self.name?= firstName

print(self.name)
/ *
打印nil,因为它包装了firstName当
传入时可选。

例如可选<零>在函数中解包到nil并分配给
* /

对自定义运算符?我试图限制左手参数不是可选的,但对于泛型的类型限制是不可能的。

问题(正如你已经正确识别的那样)是因为左边的参数类型是 T ,当你向它传入一个可选参数 T 将被推断为可选<无论> 。因为右侧的参数是 T?(并且因为类型可以自由地提升为可选项),所以它将推断类型为可选< Optional< ;无论>> ,导致您观察到的令人困惑的双包装。



解决方案是添加一个超载来处理

  infix operator?= {} 
func?=< ; T>(在左边:T,右边:T?){
如果让右=右{
左=右
}
}

//超负荷处理可选的左手边
func?=< T>(inout left:T?,right:T?){
if right right = right {
left =右



$ b $ p $(注意在Swift 3中, inout 应该出现在参数类型之前)



现在,如果您使用此运算符作为左手参数,Swift将使用该参数重载版本,而不是原始版本,因为它总是倾向于特定于类型的签名。这意味着右侧不会包含在double可选项中,因为它现在与左侧参数完全相同。

var name:String? =Bob
var firstName:String? =无

名字= =名字

print(name)// prints:可选(Bob)

请注意,这与 ?? 所做的相似,它有两个定义来处理一方的存在可选,一边是非可选的&双方都是可选的,以避免产生双重包装的选择权:

  @warn_unused_result 
public func ??< ; T>(可选:T,@autoclosure defaultValue:()throws - > T)rethrows - > T

@warn_unused_result
public func ??< T>(可选:T?,@autoclosure defaultValue:()throws - > T?)rethrows - > T'


I would like to simplify the constant need to do

if let firstName = firstName {
     self.name = firstName
}

A possible custom, generic operator to do this would be

infix operator ?= {}
func ?= <T>(inout left: T, right: T?) {
    if let right = right {
        left = right
    }
}

to simplify the previous example to

self.name ?= firstName

This creates an issue where if firstName's value is nil, then Swift will wrap the value in an optional.

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

Any possible fix to the custom operator? I attempted to limit the left-hand parameter to not be an optional but that is not possible with generic's type constraints.

解决方案

The problem (as you've correctly identified) is that because the left hand side argument is of type T, when you pass an optional into it T will be inferred to be Optional<Whatever>. Because the right hand side argument is T? (and because types can be freely promoted to optionals), it will infer the type to be Optional<Optional<Whatever>>, leading to the confusing double wrapping you're observing.

The solution is to add an overload to deal with the situation when the left hand side argument is also an optional.

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

(Note that in Swift 3, inout should appear before the parameter type)

Now if you use this operator with an optional as the left handed argument, Swift will use the overloaded version instead of the original version, as it'll always favour the more type-specific signature. This means that the right hand side won't get wrapped in a double optional, as it's now of the exact same type as the left hand side argument.

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

name ?= firstName

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

Note that this is similar to what the ?? does, it has two definitions to deal with one side being optional, one side being non-optional & both sides being optional in order to avoid the generation of double wrapped optionals:

@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?

这篇关于自定义运算符来简化If-Let的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆