快速,更优雅的代码:自动闭合

到目前为止,您已经熟悉“闭包”的定义以及它的基本用法,但是您感觉可以通过了解使用闭包还可以做些什么来扩大您的熟悉程度,这篇文章非常适合您!

就个人而言,我发现闭包是Swift中最酷的功能之一,我相信使用闭包可以使代码更具表现力,响应能力强并且易于处理。 甚至标准函数也被视为特殊的闭包(称为闭包)。

什么是自动关闭?

第一次阅读有关自动关闭的信息时,我发现它在理解使用它的目的时有些困惑,直到我发现没有必要对此进行过多思考,这确实很简单。

苹果将​​自动关闭定义为:

自动闭包是一种自动创建的闭包,用于包装将作为参数传递给函数的表达式。 它不带任何参数,并且在调用它时,它返回包装在其中的表达式的值。 这种语法上的便利性使您可以通过编写正则表达式而不是显式闭包来省略函数参数的花括号。

实际上,它仅是用于传递闭包作为参数的语法糖 。 将自动闭合功能作为函数参数传递时,不必键入花括号!

如何实现自动关闭?

实际上,您不希望将闭包本身作为参数传递给它,它与将闭包作为参数的函数有关。 通过将闭包参数标记为@autoclosure

func perform(closure:@autoclosure()->())

您正在告诉编译器closure 是一个自动关闭功能,就这么简单!

为什么要使用自动关闭?

如上所述,在“什么是自动闭合?”中,在某些情况下,将闭合作为参数传递而没有花括号的情况变得更加方便。 我认为使用自动关闭功能的最佳位置之一是运算符

例:

为了使它更清楚,让我们来看一下这种情况:

想象我们正在开发与组织人力资源系统有关的产品的一部分,其中包含Employee 结构为:

  struct Employee { 
var id:Int
变量名称:字符串
可变薪水:UInt
}

并已要求新的要求为:

我们需要创建一个运算符为( -! )来递减员工工资,应按以下方式使用它:

员工-!

金额将基于许多因素进行计算。 但是,如果雇员的工资少于1000,则什么也不会发生

太酷了! 我们将新的( -! )运算符称为“减量运算符”。 因此,我们将其实现为:

 中缀运算符-! 
扩展名员工{
静态函数-!(lhs:inout Employee,rhs:()-> UInt){
如果lhs.salary> 1000 {
lhs.salary-= rhs()
}
}
}

根据上述要求,我们对减量运算符的实现似乎很好。 但是,当尝试使用它时,我们会注意到必须编写一个“丑陋”的代码😥:

  var jack = Employee(id:101,name:“ Jack Thompson”,薪金:2000) 
杰克-! {100} //这些花括号是什么!print(jack)
//雇员(编号:101,姓名:“杰克·汤普森”,薪水:1900)

尽管可以正常工作,但是键入“ {}”的必要性不合适,我们如何摆脱它呢? 好吧,这正是将闭包标记为@autoclosure的目的。 我们要做的就是将减量运算符方法签名更改为:

 静态函数-!(lhs:inout Employee,rhs:@autoclosure()-> UInt) 

因此我们将能够:

 杰克-!  100 

我们的减量运算符现在可以更自然地使用了!

侧边栏提示:

关于我们如何实现减量运算符,您可能想知道:

为什么我们需要将右侧声明为( @autoclosure ()-> UInt )而不是直接声明为( UInt )?

通过这样做,我们可以将操作符实现为:

 静态函数-!(lhs:inout Employee,rhs:UInt){ 
如果lhs.salary> 1000 {
lhs.salary-= rhs
}
}

暗示:

 杰克-!  100 

应该工作正常。

好问题! 👍

其背后的原因是闭包被懒洋洋地评估。 在我们的案例中, 当雇员的薪水超过1000 时才需要评估右侧,因此将rhs声明为UInt而不是@autoclosure ()-> UIntgetAmountToDecrmement()会导致始终对其进行评估,即使员工工资少于1000!

你不相信吗? 让我们通过检查两种情况的日志来进行尝试:

  • 如果将减量运算符声明为static func —! (lhs: inout Employee, rhs: UInt) static func —! (lhs: inout Employee, rhs: UInt)
  func getAmountToDecrmement()-> UInt { 
print(“考虑到这里有很多要计算的…”)
返回101
} var erik = Employee(id:102,名称:“ Erik Smith”,薪水:500)
埃里克-! getAmountToDecrmement()print(erik)
//员工(id:102,姓名:“ Erik Smith”,薪水:500)

此时,它将记录:

 考虑到这里有很多要计算的… 
员工(id:102,姓名:“ Erik Smith”,工资:500)

如您所见,“ 考虑到这里有很多要计算的东西…… ”已经打印出来,而没有降低工资( Erik工资小于1000)。

  • 如果将减量运算符声明为static func —! (lhs: inout Employee, rhs: @autoclosure ()-> UInt) static func —! (lhs: inout Employee, rhs: @autoclosure ()-> UInt)
  var erik = Employee(id:102,名称:“ Erik Smith”,薪水:500) 
埃里克-! getAmountToDecrmement()print(erik)
//员工(id:102,姓名:“ Erik Smith”,薪水:500)

它会记录:

 员工(id:102,姓名:“ Erik Smith”,工资:500) 

如果没有“ 考虑,这里有很多要计算的…… ”。

与第一种情况不同,因为rhs 是一个闭包,其评估会延迟到需要使用该参数之前。

包起来:

使用自动关闭功能使我们的代码更加自然。 作为一个非常简单的示例,Swift逻辑AND运算符( &&)声明为:

  func && (lhs:T,rhs:@autoclosure()-> Bool)->布尔 

因为如果是lhs ,则无需评估rhs (结果为false )。 作为开发人员,我们正在优雅地使用它,甚至不关心它是否处理闭包,这在使用这种方法时很明显。

不要犹豫在正确的地方使用自动关闭功能,它们比吓人还要简单👻。

参考:

Swift编程语言-闭包:自动闭包。

作者✍️

欣赏您的反馈👏敬请关注更多“快速,优雅的代码”主题。

谢谢阅读!