# Day6--一个很难驾驭的概念:闭包

闭包(closure)大概是我在函式这个单元过後,卡的稍微久一点的一个关卡,主要是弄不清楚闭包到底跟函式有什麽区别,但时间久了之後,可能就会稍微忘掉闭包的一些小基础,所以闭包这个单元会大致上分成二个部分:

  1. 基础的闭包样态
  2. 省略很多东西的闭包

本篇会先描述第一种。

闭包的基础样态

  1. 函式的样子
    函式基本上就是上述图片第一个样子,它会先宣称它是func开头
    呼叫的时候,除非在写函式的时候以”_”作为外部参数,否则不能省略外部参数。
  2. 闭包的样子
    闭包则是先以let or var 作为开头,然後直接先指定後面的东西 “={}”
    呼叫的时候,直接将值放进去呼叫闭包的()里就可以了。
    闭包里的参数
    不过,光是上一张图片那样描述的闭包可能还不够,闭包有更多的内容是关於参数的,尤其是在{}里的参数型别设定

而闭包的参数传入型别与传出值型别设定,都依靠着in这个标记来读取前面的参数功能,清楚表明参数的传入值与传出值是什麽。

  1. 只传入值的闭包

  1. 有传出值的闭包
    跟函式一样,只要有传出值型别,如(game:String)->String这样的样态,就必须在闭包内部加上Return。
    而呼叫闭包的时候,稍微有一点不一样的则是,带入值的时候不需要像函式一样还要加上外部参数名称,直接将「值」放进去里面就可以了,如下述的game_comment(“Hades”)就是直接把“Hades”放进去。

其实逻辑都跟函式有点相近,但闭包的语法,其实有更大的重点在於传入值型别与传出值型别的描述,像你可能会看到的String->() or (String)->String,这个东西的重要性是闭包在运作的过程里,最核心的一环。

闭包作为参数

所以,我们大致上知道影响闭包的运作,有很大一部分是in标记之前的传入值型别与传出值型别描述,因此,上述提到的有两种:

  1. 第一种是有值传入
  2. 第二种是有值传入,也有值传出

而现在要描述的第三种比较特别,是闭包作为参数(closures as parameter):

如上面程序码写的,先把一个闭包的内容定义好,传入型别、传出型别也对应好要传入的函式,然後,再把定义好的函式,将闭包的内容丢进去函式的呼叫里面。

当然,闭包跟函式的组合可以很复杂,复杂到想要哭,不过,这边就简单的介绍,往後如果有更多的案例,可以继续在後面的文章继续的看到。
综合上述,闭包和函式很像,但是闭包可以有更多功用,像是闭包可以作为参数这点,传入函式就非常的好用,甚至可以在未来写程序的时候创造复杂性。

尾随闭包(Trailing closure syntax)

尾随闭包这件事情很有趣,它是一个极度省略的概念(如果就表象上看起来啦),假若今天有个函式长这样:

闭包在里面叫做action,传入型别为()->Void
一般我们在呼叫这个函式的时候,照理来说应该长得像下面这个样子,所有的东西都会好好地显示在画面上:

正常的函式呼叫

但尾随闭包不是这样,它会把闭包的部分省略掉,也就是说,在下面这个尾随闭包的案例中,闭包的部分因为型别是()->Void,所以可以这样做:

尾随闭包的函式呼叫

工程师真是一种奇怪的东西,东省西省,不过确实如果仔细读意思的话,我们可以很清楚的知道,省略的东西就是所谓闭包的部分。

只有一个闭包在里面的情况

不过,假如今天我们只有一个闭包在函式里面的话,我们在呼叫函数的时候,假若里面什麽东西都没有要传进去的参数或值,可以把函式的括号部分省略,变成下面这个样子:

总而言之,尾随闭包几乎可以说是一个省略东西的状态,但却也让呼叫的时候,更清楚的知道,尾随在呼叫函式後的内容,就是所谓的闭包的部分了。

省略很多东西的闭包

假如我们新增一个函式如下,但它有个「传入型别跟传出型别都是String」的闭包叫action:

这时候,我们开始呼叫闭包,我们可以很清楚的知道,呼叫的时候,func travel( )的func、( )少掉了,func本来就可以省略,而( )则因为里面没有其他重要参数,所以也省掉了,後面就是一个引数的内容,藉由in隔开了(place:String)->String

但因为在宣告函式的时候,就已经宣告了型别的传入与传出,所以Swift会认定呼叫闭包的时候传入、传出型别都是String,所以可以在步骤一中省略引数型别,

在步骤二中,省略传出型别:

步骤三中,整个都省略,因为一定会回传String这个这个值,Swift知道,所以这回连return也可以省略,毕竟它是一定会回传的东西,
而在return中的place的位置,可以藉由$0取代,这个叫做参数名称缩写,然後我记得如果有多少个参数,就可以依序以$0、$1、$2……等等的命名。

不过要记得一件事情:这种替代是方便开发者做事情,而不要看到看起来很简便,就一直用,如果参数没有几个的话,这样用是很方便的,但假若多起来,可能就不是那麽好管理的一件事情了。

tags: 铁人赛

<<:  [Day 06] 监控、维护 — 自己开一家徵信社吧!

>>:  Day6 NiFi - Processors

Day 13 - 物品借用纪录系统 (3) 程序码解说

今天主要是来补足 Day11 和 Day12 简(ㄏㄨㄚˊ)约(ㄕㄨㄟˇ)的部分。 我们会讲两个东西...

#3-打字特效炫起来!(CSS Animation)

昨天的第三个按钮动态提案:文章传送门 使用了CSS动态的动态的主菜——Animation。 其实有很...

架站:Wordpress

为何选择Wordpress? 虽然内容管理系统(CMS)也有其他的选择(例如 Joomla!),但整...

[Day_18]回圈与生成式 - (4)

回圈结构特殊指令的使用-break、continue与else 回圈在特殊需求下可以适用break、...

专案小帮手- Vue CLI

前言 Vue CLI 是用来快速建置 Vue 开发环境的一套工具,它是由 Vue.js 团队所建立的...