函數是用來完成特定任務的獨立的代碼塊酒甸。可以給函數起一個名字赋铝,用于標識一個函數插勤,當函數需要執(zhí)行的時候,這個名字就會用于"調用"函數革骨。
?在swift中农尖,每個函數都有一種類型,包括函數的參數值類型和返回值類型良哲。你可以把函數類型當做和其他普通變量類型一樣處理盛卡,這就可以更簡單的把函數當做其他的函數的參數,也可以從其他函數中返回函數筑凫。
一滑沧、函數定義與調用
- 函數的定義與調用喇颁。
func
是函數的關鍵字,參數是在函數名后的括號中嚎货,指定函數返回值類型時橘霎,用返回箭頭->
后面跟著返回類型的方法是來表示。
/**
func前綴即表示為函數
函數名: sayHello
參數名: persionName殖属,類型是String
返回值: 返回值是String類型的
*/
func sayHello(personName:String) -> String {
let getString = "hello," + personName;
return getString;
}
// 函數的調用
let str = sayHello("EndEvent");
print(str);
輸出結果: hello,EndEvent
二姐叁、函數參數與返回值
- 無參函數,即函數可以是沒有參數的:
func speak() -> String{
// 返回字符串
return "hello Swift!";
}
// 函數調用
print(speak());
輸出結果: hello Swift!
- 多參函數洗显,多個參數以
,
逗號分隔:
// 參數1: name; 參數2: age;
func sayHi(name:String, age:Int) -> String {
return "hi外潜,我叫\(zhòng)(name),今年\(age)歲.";
}
print(sayHi("EndEvent", age: 20));
輸出結果: hi挠唆,我叫EndEvent处窥,今年20歲.
- 無返回值函數,即沒有返回值:
func sayBye(name:String) {
print("Bye \(name)!");
}
sayBye("EndEvent");
// 輸出結果: Bye EndEvent!
(備注: 雖然沒有返回值定義玄组,但實際`sayBye(_:)`函數依然是返回了值滔驾。這是一個特殊的返回值,叫`void`俄讹。其實返回是一個空的元組`tuple`哆致,沒有任何元素可以寫成`()`)
- 多重返回值函數,可以用元組(
tuple
)類型讓多個值作為一個復合值返回:
// 該函數中帶3個參數患膛,返回值是一個元組
func getMaxAndMinValue(a:Int, b:Int, c:Int) -> (max:Int, min:Int){
// 計算最大值的方法(系統(tǒng)自帶)
let maxValue = max(a, b, c);
// 計算最小值的方法(系統(tǒng)自帶)
let minValue = min(a, b, c);
return (maxValue,minValue);
}
let temp = getMaxAndMinValue(10, b: 3, c: 11);
// 因為元組成員值已命名摊阀,即可用點語法
print("maxValue:\(temp.max)");
print("minValue:\(temp.min)");
輸出結果:
maxValue:11
minValue:3
- 可選元組返回類型。如果函數返回的元組類型踪蹬,可能整個元組都是"空的",那么久可以使用* 可選的(Optional) *元組進行返回胞此,這就表示整個元組是
nil
。例如(Int, Int)?
跃捣、(String, String)?
漱牵。
func getMaxAndMinValue(array: [Int]) -> (max: Int, min: Int)? {
if array.isEmpty { // 表示數組為空
return nil
}
var currentMin = array[0]
var currentMax = array[0]
// 遍歷數組
for value in array[1..<array.count] {
if value < currentMin {
currentMin = value
} else if value > currentMax {
currentMax = value
}
}
return (currentMax, currentMin)
}
// 函數調用,不為空才打印輸出
if let temp = getMaxAndMinValue([10,3,13,100,-50]) {
print("maxValue:\(temp.max)");
print("minValue:\(temp.min)");
}
輸出結果:
maxValue:100
minValue:-50
注意: 可選元組類型如
(Int, Int)?
和 元組中包含可選類型如(Int?, Int?)
是不一樣的枝缔〔几恚可選的元組類型蚊惯,整個元組是可選的愿卸,而不是元組中的每個元組值。
三截型、函數參數名稱
函數參數都有一個* 外部參數名 和 一個 局部參數名 *趴荸。外部參數名用于在函數調用時標注傳遞給函數的參數,內部參數名在函數的內部使用宦焦。
?一般情況下发钝,第一個參數省略其外部參數名顿涣,第二個以及隨后的參數使用其局部參數名作為外部參數名。所有局部參數名必須是獨一無二的酝豪。盡管多個參數可以有相同的外部參數名涛碑,但不同的外部參數名可以提高代碼的可讀性。
- 指定外部參數名
// firstName: 第一個參數的外部參數名
// name: 第一個參數的內部參數
func sayHello (firstName name:String) {
print("hello \(name)");
// 錯誤的孵淘,因為外部參數只用于標注傳遞
// print("hello \(firstName)");
}
// 有提供外部參數名蒲障,在調用時,必須使用外部參數名!!!
sayHello(firstName: "EndEvent");
輸出結果: hello EndEvent
// 外部參數名和內部參數名可以是一樣的
func sayHello (name name:String) {
print("hello \(name)");
}
sayHello(name: "EndEvent");
輸出結果: hello EndEvent
// 所有外部參數名都可以是一樣的瘫证,即都為name
// 內部參數名是要在函數內使用揉阎,所以必須是不同
func sayHello (name name1:String, name name2:String) {
print("hello \(name1)");
print("hello \(name2)");
}
sayHello(name: "EndEvent", name: "Swift");
輸出結果:
hello EndEvent
hello Swift
- 忽略外部參數,如果不想為第二個以及后續(xù)的參數設置外部參數名背捌,可以用
_
來代替一個明確的參數名:
// 第一個參數默認忽略其外部參數名稱毙籽,顯式寫下劃線是多余的
func sayHello (name1:String, _ name2:String) {
print("hello \(name1)");
print("hello \(name2)");
}
sayHello("EndEvent", "Swift");
輸出結果:
hello EndEvent
hello Swift
- 默認參數值,即可以給函數體中每個參數定義
默認值
毡庆。如果有默認值坑赡,在調用的時候可以忽略此參數:
// 參數style是有默認值的
func goHome (name: String, style: String = "走路") {
print("\(name)是\(style)回家的");
}
goHome("EndEvent"); // 可以忽略style參數
goHome("Swift",style: "飛");
goHome("liming", style: "開車");
輸出結果:
EndEvent是走路回家的
Swift是飛回家的
liming是開車回家的
注意: 將帶有默認值的參數放在函數參數列表的最后,這可以保證在函數調用時么抗,非默認參數的順序的一致性垮衷,同時在相同函數在不同情況下調用時顯得更為清晰。
- 可變參數乖坠,
可變參數
表示可以不接收或接收多個值搀突。通過在變量類型們后加入...
的方法來定義可變參數:
// 計算平均值方式,參數是可變的
func arithmeticMean(numbers:Int...) -> Float {
var total:Float = 0;
var sum = 0;
for number in numbers {
sum += number;
}
total = Float(sum) / Float(numbers.count);
return total;
}
let total = arithmeticMean(1,2,3,4,5,6,7,8,9);
print(total);
輸出結果: 5.0
注意: 一個函數中最多只能有一個可變參數熊泵。
- 常量參數和變量參數仰迁。函數參數默認是常量,試圖在函數體重修改參數值這會導致編譯出錯顽分。但有時候如果想修改參數值徐许,那么久可以將參數定義為變量參數:
func myAppend(var str:String) -> String {
str.appendContentsOf(" --- haha");
return str;
}
print(myAppend("EndEvent"));
輸出結果: EndEvent --- haha
注意: 對于變量參數,在函數調用結束后便會消失卒蘸,即是變量參數僅僅存在于函數調用的生命周期中雌隅。
- 輸入輸出參數。如果想要在一個函數可以修改參數的值缸沃,并且在函數調用結束后仍然存在恰起,即可以把這個參數定義為* 輸入輸出參數(In-Out Parameters) *
// 值的交換
func swapTwoInts(inout a:Int, inout b: Int) {
let tempValue = a;
a = b;
b = tempValue;
}
// 定義兩個變量,并初始化
var a = 10;
var b = 30;
// 調用函數交換兩個變量的值
swapTwoInts(&a, b: &b);
print("a = \(a)");
print("b = \(b)");
輸出結果: a = 30 b = 10
注意:輸入輸出參數和返回值不一樣趾牧,其實這就是將變量的地址傳過去检盼,在函數體中通過變量的地址進行修改值。
四翘单、函數類型
每個函數都有特定的函數類型吨枉,由函數的參數類型和返回值類型組成蹦渣。
- 使用函數類型。在swift中貌亭,使用函數類型就像使用其他類型一樣:
// 相加函數
func sumFunc(a:Int, b:Int) -> Int {
return a + b;
}
// 相乘函數
func mathFunc(a:Int, b:Int) -> Int {
return a * b;
}
// 定義變量str柬唯,類型為(Int,Int) -> Int
var str:(Int,Int) -> Int = sumFunc;
// 調用相加函數
print("10 + 20 = \(str(10, 20))");
// 給str這個變量賦值一個函數
str = mathFunc;
// 調用相乘函數
print("10 * 20 = \(str(10, 20))");
輸出結果: 10 + 20 = 30 10 * 20 = 200
- 函數類型作為參數類型。即你可以將(Int, Int) -> Int這樣的函數類型作為另外一個函數的參數類型:
// 相乘函數
func mathFunc(a:Int, b:Int) -> Int {
return a * b;
}
// 輸出函數
func printMathFuncResult(mathFunc:(Int, Int) -> Int, a:Int, b:Int){
print("\(a) * \(b) = \(mathFunc(a,b))");
}
// 調用輸出函數
printMathFuncResult(mathFunc, a: 10, b: 10);
輸出結果: 10 * 10 = 100
注意: 可能認為這和函數調用效果是一樣圃庭,現在這是否多此一舉权逗?其實不是,
printMathFuncResult (_:_:_:)
函數作用是輸出另外一個適當類型的數學函數的調用結果冤议。即在這里只關心傳入的函數類型是否正確斟薇,而不在意函數如何實現。printMathFuncResult (_:_:_:)
就是以一種安全類型(type-safe)
的方式恕酸,將部分功能轉給調用者實現堪滨,也即是方便代碼的封裝。
- 函數類型作為返回類型蕊温「は洌可以將函數類型作為另外一個函數的返回類型:
// 實現功能: 將currentInput值變?yōu)?的過程
var currentInput = -5;
// 加操作
func stepForward(input:Int) -> Int {
return input + 1;
}
// 減操作
func stepBackward(input:Int) -> Int {
return input - 1;
}
// 函數選擇,參數為input义矛,返回值為'(Int) -> Int'類型
func chooseStepFunction(isBackward:Bool) -> (Int) -> Int {
// YES:即表示currentInput值是大于0的发笔,選擇stepBackward減操作
// NO: 即表示currentInput值是小于0的,即選擇stepForward加操作
return isBackward ? stepBackward : stepForward;
}
// 循環(huán)操作凉翻,直到currentInput為0
while currentInput != 0 {
print("currentInput: \(currentInput)");
// 根據currentInput值了讨,選擇對應操作的函數
var moveNearerToZero = chooseStepFunction(currentInput > 0);
// 調用操作
currentInput = moveNearerToZero(currentInput);
}
print("結束操作:\(currentInput)");
輸出結果:
currentInput: -5
currentInput: -4
currentInput: -3
currentInput: -2
currentInput: -1
結束操作:0
五、嵌套函數
在本節(jié)文章中你說見到函數都是* 全局函數(global functions) 制轰,它們都是屬于全局域的前计。但你也可以將函數定義在函數體中,而這種稱之為 嵌套函數(nested functions) 垃杖。
? 嵌套函數 ,在默認情況下對外界是不可見的男杈,但卻可以被它們的 外圍函數(enclosing function) *調用。并且外圍函數也可以返回其所嵌套的函數调俘,使得這個函數也可以在其他域中被調用伶棒。
// 實現功能: 輸入一個值,將值變?yōu)?的過程
var currentInput = -5;
// 函數選擇 - 全局函數
func chooseStepFunction(isBackwark:Bool) -> (Int) -> Int {
// 加操作 - 嵌套函數
func stepForward(input:Int) -> Int {
return input + 1;
}
// 減操作 - 嵌套函數
func stepBackward(input:Int) -> Int {
return input - 1;
}
return isBackwark ? stepBackward : stepForward;
}
// 即是接受'(Int) -> Int' 類型的函數
let moveNearerToZero = chooseStepFunction(currentInput > 0);
// 循環(huán)操作彩库,直到currentInput為0
while currentInput != 0 {
print("currentInput: \(currentInput)");
currentInput = moveNearerToZero(currentInput);
}
print("結束操作:\(currentInput)");
輸出結果:
currentInput: -5
currentInput: -4
currentInput: -3
currentInput: -2
currentInput: -1
結束操作:0