Swift函數
在編程中,我們常把能完成某一特定功能的一組代碼,並且帶有名字標記類型叫做函數,在C語言中,我們知道函數名就是一個指針,它指向了函數體內代碼區的第一行代碼的地址,在swift中也具有同樣的功效。
在Swift中函數的表現形式如下:
1. func 函數名(參數名1:參數類型,參數名2,參數類型)->返回值類型 {函數的實現部分}
func sayHello()->Void {
print("hello world")
}
//有參數,有返回值,
func sayHello2(personName:String)->String {
let msg:String = "hello" + personName + "!"
return msg
}
sayHello2("a gan zuo")
// 有參數 無返回值
func showPersonInfo(personName:String,personAge:Int) ->Void {
print("\(personName)今年\(personAge)歲")
}
showPersonInfo("ZhangShan", personAge: 20)
//統計一段字符中制定字符的個數
let String = " I like you,I miss you,I love you,I hate you ,I wed you"
func count(str:String) -> (me:Int,you :Int other:Int) {
var m = 0,y = 0, o = 0
for char in str.characters {
switch char {
case "I":
m++
case "u":
y++
default:
o++
}
}
return (m,y,o)
}
let showCharacterCount = count(String)
showCharacterCount.0
showCharacterCount.me
2. 函數參數的內部名和外部名之分, 其本質作用就是為了再調用函數時候能看到這個參數標示的是什麽值,例如 是年齡的值,還是是名字的值
func fa1(innerName: Int) { innerName為函數的內部名,第一個參數如果前面只有一個標示類似於這樣就叫做內部名 }
函數的外部名,只能在函數外部使用,函數的內部名只能在函數的內部使用,在內部名前面加上一個空格和一個字符串標識就成了外部名
func fa(exteraName innerName:LocalName:Int) {
print("inner name:\(innerName)") //此處如果換成外部名 exteraName 則程序會報錯
}
fa(externaName:123) // 外部名externaName只在外部做屬性內容標示時使用
函數的從 第二個參數開始 及以後的參數默認即是內部名,又是外部名
func show(name:String, age:Int) {
//第一個name為內部名, 第二個age為內部或者外部名
print("\(name)的年齡是\(age)")
}
show("zhangshan", age: 31)
/**如果不希望使用默認的外部名,可以自己起外部名,在內部名的前面起一個名字空格隔開就是外部名*/
func pointWithX(x:Int ,AndY y:Int) {
print("point(\(x),\(y))")
}
pointWithX(3, AndY: 2) //此處在默認的第二個參數前加上了 AndY空格標示更改了原來的外部名 y,而第一個參數默認是內部名,所以前面沒有標示。
/**如果不希望顯示外部名,則在外部名前面擠上 萬能數字 _ 下劃線 */
func point(x:Int, _ y:Int) { }
point(100,200)
3. 函數的默認值,一個函數的參數可以設一個默認值,如果這個參數沒有傳入值,則使用默認值,如果傳入了就使用新的值。
func printArray(array:[Int] ,separate:String = ",",flag:Bool) {
if flag { print "["}
for var i = 0;i <array.count - 1;i++ { print("\(array[i]\(separate))")}
if flag{print("]")}
}
var array = [9,5,2,7]
printArray(array,flag:ture) //使用默認值
printArray(array,separate:"_",flag:ture) //不使用默認值
/**函數的可變長參數,使用 類型名+ ... 表示有一堆這種類型的參數*/
fun getAvg(numbers:Double...) ->Double {
var total = 0.0
for num in numbers {
total += num
} return total/Double(numbers.count)
}
getAvg(2.0,3.0,8.0)
/**C語言中的可變長參數
#include <stido.h>
#include <stdarg.h>
float sum(int n,...) { //n代表元素的個數,....代表可變參數
va_list p; //定義了一個指針p
va_start(p,n) //定義了指針開始的元素位置
for (int i = 0; i<n; i++) {
sum += va_arg(p,double) //va_arg每調用一次p指針後移動一個元素
}
}
*/
4. 函數的重載的條件,
a.有兩個及兩個以上的方法,且方法名相同,參數個數,參數類型,參數順序不同均滿足
b.參數列表不同,參數外名不通,都可以形成重載關系
//有參與無參數
func test1(){}
func test1(a:Int){}
func test2(a:Int) {}
func test2(a:Int,b: Int) {}
func sayHello(a:String,b:Int) {}
fun sayHello(b:String,a :Int) {}
fun test3(a:Int,b :String) {}
fun test3(a:Int,B b:String) {}
5. 函數的類型*******重點,當一個函數聲明部分,去掉了函數名字,那麽剩下的部分就函數了
var x:Int //Int 類型變量
void test(){} void() //C函數類型 void(*pfun)() //C函數指針類型
Int getMax(int x,int y) //int (int x,int y)類型,int(*pfun)(int x,int y) //函數的指針類型
func sayHello() { print("hello")}
// ()->(Void):Swift中無參無返回值的類型,void可以省略,代表沒有參數,與C語言中Void相似。
下面定義了一個(Int,Int)->Int 型的函數,能指向這一類型的函數,我們可以通過構造這種類型函數的不通邏輯,來實現加 減 乘 除
func addTwoInts(a: Int,b :Int)->Int { return a + b}
func addTwoInts(a: Int,b: Int)->Int { return a - b}
//函數也可以作為一種變量來進行賦值,將一個函數賦值給另外一個變量,根據前面學到過的Swift自動推算類型,左邊被賦值的變量也變成了和它具有一樣功能的函數了
var function = subTwoInts //函數指針賦值。
var function1:(Int,Int) ->Int = addTwoInts //同前面所學的類型標註,函數名也可以拿來作為類型標註。
function2(100,200) //無類型標註,我們看不到第二個參數的 外部參數名
function(100, b:200) //賦值時有使用函數類型標註,我們可以看到第二個參數的外部名
//定義一個函數,賦值sayHello要求帶一個類型標註,帶一個參數
func sayHello(content:String) { print("\(content)")}
var function3:(String) ->() = sayHello
function3("hello baby!")
/** 定義一個函數,賦值sayHello要求類型標註,不帶參*/
func sayHello2() {
print("no arguments,no return values")
}
var function4:()->() = sayHello2
function4()
//下面主要進行無參無返回值的變換,根據標註類型的不同進行變換
var function5:()->(Void) = sayHello2
var fucntion6:(Void)->(Void) = sayHello2
var function7:Void ->Void = sayHello2
var function8 = sayHello2 //此步驟需要先知道sayHello2的函數類型,自動推導獲得,相比OC最大的進步也就是自動推導了
function8()
//寫一個整形參數,返回兩個數的乘積
func mulTwoInts(a :Int,b :Int) ->Int { return a * b } //當代碼中只有一行語句時,可以省略return關鍵字
// 寫一個函數,傳入一個函數類型參數。
func getResult(function:(Int,Int)->Int)->Int { //在C中常是這樣定義的int (*p)()(int,int)
let result = function(a,b)
return result
}
/**下面通過給getResult函數傳入一個(Int,Int)->Int類型的函數 作為參數,內不調用該傳入的函數,然後再傳入 定義好的a,b變量*/
var a=100,b =99
func getResult(function:(Int,Int) ->Int) ->Int { let result = function(a,b) return result}
getresult(addTwoInts)
getresult(sunTwoInts)
getresult(mulTwoINts)
getresult { (a,b) ->Int in return a* b}
/** 函數數組 數組中的每個元素都是函數,c語言中對應的叫函數數組*/
var nums:[Int] = [1,2,3,4,5,6] ; nums[0]
var funs:[(Int,Int)->Int] = [addTwoInts,subTwoInts,mulTwoInts]
funs[0](100,200)
funs[1](100,200)
funs[2](100,200)
// 函數座位一個函數的返回值類型,此處定義了一個函數做為返回值。這個和OC中的Block做返回值還是有幾分像
func test()->(Int,Int)->Int {
return addTowInts //只需要返回類型的函數 返回就可以了,這裏對應的返回值函數類型 (Int,Int)->Int
}
/** 嵌套函數,如果傳真則是返回加法函數,如果為假則返回其它函數*/
func twoInts(isAddBool)-> (Int,Int)->Int {
//此處我們除了可以使用已經定義好的 addTwoInts 和subTwoInts函數,還可以在此函數內部定義輔助函數,也可以作為私有函數,它的作用閾就限定在這個 {} 內
func addTwoInt2 (a :Int, b:Int)->Int ){ return a + b }
func subTwoInt2 (a: Int, b:Int)-> Int){ return a - b }
if isAdd { return addTwoInt2} else { return subTwoInts}
}
twoInts(ture)(100,200) //註意此處,實際是先調用TwoInts(ture) 此時返回一個 addTwoInt2函數
然後次函數傳入(100,200)這兩個參數相當於再調用addTwoInt2(100,200) 可得結果為300
6. 函數的閉包,Swift中重點之重點.
下面我們首先來了解一下它在其它語言中的表現形式:
Swift ---- Closure 閉包
Ruby OC -----Block 代碼塊
C++ -----Lambda 演算
javascript ------anonymous function 匿名函數
它的本質就是將一段代碼封裝起來,變成一個類似於變量的玩意;在Swift中如果一個 函數的參數 是 函數類型,那麽可以將一個功能相同的代碼(閉包)傳給它。OC中的Block不能傳函數類型,但可以傳代碼 。所以說閉包可以理解為函數,但是比函數的功能要多的多。
基本語法格式:
{ (參數列表)->返回值類型 in 執行代碼語句}
而OC中Bloc的主要表現形式
^ 返回值類型(參數列表) {執行代碼語句 }
//定義一個函數類型,或者是閉包類型,如下所示,只要函數類型與 閉包中 參數表->返回值類型 相同就可以警醒函數賦值。而 函數的實現體部分代碼 即為 閉包內 in後面的代碼
var sayClosure:(Int,Int)->Int;
sayClosure = {(x :Int,b: Int)->Int in return x + y }
sayClo(100,200)
/** OC中Block定義方式 定義上面的閉包函數
int (^sumBlock)(int,int);
sumBock = ^int(inta,int b){ return a + b; };
typedef double(^SumBlock)(int,int); 定義了一個SumBlock的類型
SumBlock s =^double(int i1,int i2) { return i1 + i2; };
*/
7 . Swift中的冒泡排序,實現原理 挨個取出數組前面的數,然後將該數與它後面所有的數進行比較,根據大小調換數值。
func paopaoSort(inout data[Int],function:(Int,Int)->Int) {
for var i =0;i < data.count - 1;i++ {
for var j = i+1; j< data.count; j ++ { // i+1 表示從 i後面的數開始逐個取出與i進行比較
if (function(data[i],data[j]))
swap(&data[i],&data[j]) }}}
let data:[Int] = [9,3,56,7,8]
func sortDes( a:Int, b:Int )-> Bool { return b - a }
func sortAsc( a, b) -> Bool { return a - b } //根據a,b傳入值的類型可以省略 Int ,Int
paopaoSort(&data,function: sortDes)
paopaoSort(&data,function: sortAsc)
//其它奇葩的寫法:
sortData(&data){$0 < $1} // $0表示第一個參數 , $1表示第二個參數; 再運行的時候判斷
data[i] < data[j ]
sortData(&data,function: >) //把> 做為一個函數參數整體 ; 再調用的時候相當於講function(data[i],data[j]) 替換成了 >
8. Swift中默認的函數相關用法
var names = ["aaa","ddd","fdsaf","fdsa"]
names.sort() //會自動對數組names中的元素進行排序
name.sort{ (a,b) -> Bool in return a > b} //也可以通過此方式返回a與b的比較結果決定排序順序。當sort函數或得此Bool值後,內部根據降序活著升序自動進行排序運算。
names.sort{ return $0 > $1 } //具有相同的功效
var numbers:[Int] = [1,35,5643,653]
//map方法,把數組中的每個元素都取出來,放入閉包函數中執行,把所有執行的結果放入新的數組中
//下面這句話表示從通過numbers 中取出每個元素,然後進行相加,最後返回一個所有元素+20後的新的數組
var newNumber = numbers.map{ (number:Int) in return number + 20 }
也可以寫成
var newNums2 = numbers.map({(x) -> Int in retunr x +10 })
當然還可以寫成多種方法,自己慢慢摸索去,基本之遙不報錯就Ok了
/**拖尾閉包(尾隨閉包) 如果一個函數中最後的一個參數是閉包函數或閉包函數,可以將其寫在()外面*/
如下定義的函數: 該函數中最後一個參數 function:(Int)->Int 閉包函數
func test(a:Int, b Int , function:(Int)->Int ) { }
test(100,b:200) {(x) -> Int in return x + 10 }
test(100,b:200, function:{(x)->Int in return x + 100})
Swift函數