Swift function 參數的外部名 & 內部名(argument label & parameter name)

呼叫 function 包含參數名的好處

學過其它程式語言的朋友,也許會覺得 Swift 的呼叫 function 有點怪,比方以下例子,呼叫 eat 時 ( ) 裡必須包含參數名 name & price。

func eat(name: String, price: String) {
let message = "花了$" + price + "吃" + name
print(message)
}
eat(name: "英國頂極菲力牛排", price: "2500")

其它程式語言呼叫 function 時,往往不帶參數名,例如以下例子:

eat("英國頂極菲力牛排", "2500")

為什麼 Swift 要與眾不同,要我們額外輸入參數名呢 ?

不過我們的手指並沒有比較累,因為 Xcode 的自動完成會幫我們輸入參數名

這一切都是為了增加程式的可讀性。寫成沒有參數名的 eat("英國頂極菲力牛排", "2500"), 我們很難一眼看出 2500 是 2500 元還是 2500 克 ? 除非我們特別去研究 function eat 定義的程式碼或註解。相反的,呼叫 function 時包含參數名稱,寫成 eat(name: "英國頂極菲力牛排", price: "2500"),我們一眼就能看出它是 2500 元,因為參數名幫我們理解參數的意義。

function 參數的外部名 & 內部名(parameter name & argument label)

Swift 的 function 參數不僅於此,它可以有外部名和內部名兩種名稱,就像我們在外面跟家裡也常有不同名字。

例如以下例子,我們在 function { } 裡存取的參數名是內部名(parameter name),呼叫 function 時在 ( ) 裡包含的參數名是外部名(argument label)。

也許你會覺得奇怪,剛剛的例子裡,明明外部名和內部名一模一樣呀,哪有什麼分別? 其實在定義 function eat 時,我們在 eat(name: String, price: String) 裡宣告的 name & price 是參數的內部名,而 Swift 會自動幫我們產生和內部名同名的外部名。這也是我們最常使用的情境,畢竟為參數的外部名和內部名想不同名字是很累的一 件事,就好像生寶寶想名字一樣 !

大部分的時候,我們習慣採用 Swift 預設的設計,讓參數的外部名和內部名同名。只有在某些特別的情況,為了讓程式看起來更淺顯易懂,更像人類熟悉的英文句子,我們才會另外取不同的外部名。

讓我們看看以下的例子。

func move(start: String, end: String) {
print("move from " + start + " to " + end)
}
move(start: "地球", end: "火星")

以上程式完全沒問題,執行後將印出 move from 地球 to 火星,不過呼叫 function 時寫成 move(start: "地球", end: "火星"),看起來不太像英文句子。

寫程式時寫得愈像英文句子愈好,因為愈容易讓人理解。那如果將參數名改成 from & to 呢 ?

func move(from: String, to: String) {
print("move from " + from + " to " + to)
}
move(from: "地球", to: "火星")

呼叫 function 時變成 move(from: "地球", to: "火星"),看起來像英文 句子了,但是 function 的 { } 裡卻變成 print("move from " + from + " to " + to),變成它不像英文句子了。

看來很難有一個名字同時適合 function 內部和 function 呼叫時使用。沒關係,我們還有最後的大絕招,讓參數的外部名和內部名不同名字。

宣告 function 參數時,參數的規則如下:

  • 可同時包含外部名和內部名,先外部名再內部名,以空白隔開。
  • 外部名可省略,但內部名則一定要有。只有內部名時, Swift 將自動產生同名的外部名。
func move(from start: String, to end: String) {
print("move from " + start + " to " + end)
}
move(from: "地球", to: "火星")

以上例子完美解決剛剛的問題,參數的外部名是 from & to,內部名是 start & end,,print("move from " + start + " to " + end) & move(from: "地球", to: "火星") 看起來都像英文句子了。

接著讓我們再多看一個模仿 Apple 官方的例子。

func greet(person: String, from hometown: String) -> String {
return "Hello " + person + "! Glad you could visit from " + hometown + "."
}
print(greet(person: "Bill", from: "Cupertino"))

第二個參數的外部名是 from ,內部名是 hometown。從以上的例子,我們發現參數的外部名滿常出現英文的連接詞,比方 with,on,from,to 等,因為它們能讓呼叫 function 的程式看起來更像英文句子。

iOS SDK 參數外部名 & 內部名不同的例子

iOS SDK 裡許多 function 為了增加可讀性,參數的外部名 & 內部名取不同的名字,以下讓我們看看幾個例子。

  • DateFormatter 的 function string(from:)。

參數的外部名是 from,內部名是 date。

func string(from date: Date) -> String

應用

import Foundation

let now = Date()
let dateFormatter = DateFormatter()
dateFormatter.dateFormat = "yyyy年MM月dd日"
let dateString = dateFormatter.string(from: now)

結果

2022年03月26日
  • Date 的 function advanced(by:)。

參數的外部名是 by,內部名是 n。

func advanced(by n: TimeInterval) -> Date

應用

import Foundation

var time1 = Date()
var time2 = time1.advanced(by: 60)
print(time1)
print(time2)

印出

2022-03-26 09:11:37 +0000
2022-03-26 09:12:37 +0000

AI 舉的例子

func exchangeGift(from personA: String, to personB: String) {
print("\(personA) gives a gift to \(personB)")
}

exchangeGift(from: "Alice", to: "Bob")

func orderFood(for customer: String, dish: String) {
print("\(customer) orders \(dish)")
}

orderFood(for: "小王子", dish: "牛排")

取消外部參數名(argument label)

呼叫 function 時,參數的外部名可以幫助我們理解參數的意義。不過有時我們可以一眼看出參數的意義,不需要額外的參數名稱說明。尤其是第一個參數,我們往往能從 function 名稱猜出它的意思。

例如以下例子,呼叫 function 時, eatFood(name: "美國頂級菲力牛排", price: "2500") 裡的 name 有點多餘,就算沒有 name,我們還是能猜出牛排是食物的名稱。

func eat(name: String, price: String) {
let message = "花了$" + price + "吃" + name
print(message)
}
eat(name: "英國頂極菲力牛排", price: "2500")

因此不如就省略外部參數名 name 吧。定義 function 時,將外部參數名宣告為 _ 即可省略。(ps: 在 Swift 裡當 _ 出現時,通常都和捨去、忽略有關)

func eat(_ name: String, price: String) {
let message = "花了$" + price + "吃" + name
print(message)
}
eat("英國頂極菲力牛排", price: "2500")

也因為 _ 的關係,呼叫 function 時,參數的提示輸入框有兩種,一種要帶參數名,一種不用,相關說明可參考以下連結。

iOS SDK 取消外部參數名(argument label) 的例子

開發 iOS App 時,其實很多地方都可以看到省略外部參數名,以下讓我們看看幾個不同的例子。

  • print
func print(_ items: Any..., separator: String = " ", terminator: String = "\n")

呼叫 print 時可省略參數名 items。

print("明月幾時有,把酒問青天")
  • String 的 append(_:)
func append(_ other: String)

呼叫 append 時可省略參數名 other,bestManName 變成 peter是好男人

var bestManName = "peter"
bestManName.append("是好男人")

--

--

彼得潘的 iOS App Neverland
彼得潘的 Swift iOS App 開發問題解答集

彼得潘的iOS App程式設計入門,文組生的iOS App程式設計入門講師,彼得潘的 Swift 程式設計入門,App程式設計入門作者,http://apppeterpan.strikingly.com