iT邦幫忙

2021 iThome 鐵人賽

DAY 6
0
Mobile Development

Swift30天:從語法到觀念,告訴你在踏入實作前最好弄清楚的那些事系列 第 6

# 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: 鐵人賽

上一篇
# Day5--Funny Function!一招函式打天下?
下一篇
# Day7--物件兄弟黨:類別與結構
系列文
Swift30天:從語法到觀念,告訴你在踏入實作前最好弄清楚的那些事30

1 則留言

0
Chiahsuan
iT邦新手 5 級 ‧ 2021-09-22 17:13:25

原來swift也有閉包/images/emoticon/emoticon16.gif

MJ iT邦新手 5 級 ‧ 2021-09-22 18:51:33 檢舉

閉包真的是一種可遠觀而不可褻玩焉的東東....../images/emoticon/emoticon06.gif

我要留言

立即登入留言