使用func
關鍵字定義 Function,接著宣告 Function 名稱,然後使用()
宣告參數列表,如果有回傳值則使用->
宣告回傳值的型別。
最簡單的 Function - 沒有參數,沒有回傳值。
func hi() {
println("hello")
}
hi() //output: hello
接受參數的 Function。
func hi(name: String) {
println("Hello, \(name).")
}
hi("John") //output: Hello, John.
雙重名稱的參數,內部、外部使用。
func hi(friendName name: String) {
println("Hello, \(name).")
}
hi(friendName: "John") //output: Hello, John.
參數前加#
自動產生內外同名的參數。
func hi(#name: String) {
println("Hello, \(name).")
}
hi(name: "John") //output: Hello, John.
Function 參數預設值 - 沒有傳入參數自動使用預設值。參數預設值定義後自動產生內外同名的參數,呼叫時必須加上外部參數名。
func hi(name: String = "World") {
println("Hello, \(name).")
}
hi(name: "John") //output: Hello, John.
hi() //output: Hello, world.
Function 傳入參數為常數,若要修改要另外用var
宣告。
func hi(name: String) {
name = "World" // error: cannot assign to 'let' value 'name'
println("Hello, \(name).")
}
func hi(var name: String) {
name = "World"
println("Hello, \(name).")
}
hi("John") //output: Hello, World.
Function 內部改變參數值不影響外部。
func add(var num: Int) {
num = num + 1
}
var number = 10
add(number)
println(number) //output: 10
Function 用inout
修飾參數,函式內部改變參數值同時作用到傳入的變數,呼叫函式inout
參數前要加&
。
func add(inout num: Int) {
num = num + 1
}
var number = 10
add(&number)
println(number) //output: 11
Function 可以有回傳值,透過->
告知回傳值型別。
func hi() -> String {
return "Hello, World."
}
hi() //return: "Hello, World."
Function 沒有回傳值,以下三種方式意義相同。
func foo() {}
func bar() -> () {}
func baz() -> Void {}
func hi(adjective: String, pets: String...) {
for pet in pets {
print("\(adjective)\(pet), ")
}
}
hi("可愛的", "小狗", "小貓", "小兔"); //output: 可愛的小狗, 可愛的小貓, 可愛的小兔,
Function 型別由參數型別與回傳型別共同定義。Function 型別也是型別的一種,也可以使用變數(常數)指向Function。
func add5(num: Int) -> Int {
return num + 5
}
var add: (Int)->Int = add5
add(5) //return: 10
add
變數型別為(Int)->Int
,呼叫時必須加上()
,括號內填上符合 Function 定義的參數。
Function Signature(簽名)包含函式名稱、參數名稱、參數型別、回傳型別。同名函式簽名不同可以同時存在。
func hi() {
println("hello world")
}
func hi() -> String {
return "hello world"
}
var hi_1: ()->() = hi
var hi_2: ()->String = hi
hi_1() //output: hello world
hi_2() //return: "hello world"
func hi(something: String) {
println("hello \(something)")
}
func hi(something: Int) {
println("hello \(something)")
}
hi(123) //output: hello 123
hi("world") //output: hello world
func hi(name something: String) {
println("hello \(something)")
}
func hi(food something: String) {
println("hello \(something)")
}
hi(name: "Hugo") //output: hello Hugo
hi(food: "Banana") //output: hello Banana
func hi(someone: String) -> String {
return "Hello \(someone)"
}
func hi(someone: String, other: String) -> String {
return "Hello \(someone) & \(other)"
}
hi("World") //return: "Hello World"
hi("George", "Marry") //return: "Hello George & Marry"
func foo() {
print("foo")
}
func bar() {
print("bar")
}
func repeat(count: Int, action: ()->()) {
for _ in 1...count {
action()
}
}
repeat(3, foo) //output: foofoofoo
repeat(3, bar) //output: barbarbar
repeat
裡面for-in的計數器的值不重要,用底線_
取代。action
型別為()->()
,沒有傳入參數,也沒有回傳值。repeat
的第二個的參數必須合乎()->()
的條件。func foo() -> String {
return "foo"
}
func bar() -> String {
return "bar"
}
func murmur(mood: Int) -> ()->String {
return mood % 2 == 0 ? foo : bar
}
var doStuff: ()->String = murmur(5)
doStuff() //return: "bar"
murmur()
回傳型別為 Function,定義為()->String
,沒有傳入值,回傳值為String
。murmur()
回傳值的儲存變數型別定義為()->String
。Function 包含 Function 的用法叫做 Nested Function。
func murmur(mood: Int) -> ()->String {
func foo() -> String {
return "foo"
}
func bar() -> String {
return "bar"
}
return mood % 2 == 0 ? foo : bar
}
var doStuff: ()->String = murmur(5)
doStuff() //return: "bar"
理論上外層 Function 執行完他擁有的 Context 就會消失,但 Nested Funtion 有個神奇的能力 - 回傳的 Function 可以存取以下資料:
let gloVar = "GV"
let gloCon = "GC"
func extFunc(extArg: String) -> (String)->String {
var extVar = "EV"
let extCon = "EC"
func intFunc(intArg: String) -> String {
var intVar = "IV"
let intCon = "IC"
return "access to \(intVar), \(intCon), \(intArg), \(extVar), \(extCon), \(extArg), \(gloVar), \(gloCon)"
}
return intFunc
}
var magicFunc = extFunc("EA")
magicFunc("IA") //return: "access to IV, IC, IA, EV, EC, EA, GV, GC"
Function 的參數與回傳值可以是 Optional。
func hi(name: String!) -> String? {
return name != nil ? "hi, \(name)" : nil
}
hi("hugo") //return: "hi, hugo"
hi(nil) //return: nil
Curried Function 就是直接呼叫 Nested Function 回傳的 Function,執行時會像以下範例呼叫repeat
時串接兩個()
,雖簡潔卻犧牲可讀性。
func repeat(times: Int) -> (String)->() {
func say(message: String) {
for _ in 1...times {
print(message)
}
}
return say
}
repeat(2)("Hello!") //output: Hello!Hello!
另一種 Curried Function 定義方式如下,簡單來說就是把內外兩層 Function 混在一起做撒尿牛丸。呼叫repeat
的方式和前一個範例有一點點不同,第二個()
裡面要包含參數名稱,否則會編譯錯誤。
func repeat(times: Int)(message: String) -> () {
for _ in 1...times {
print(message)
}
}
repeat(2)(message: "Hello!") //output: Hello!Hello!
方便簡潔是把雙面刃,永遠記住 "Write Code for Humans not Machines"。