在编程中,我们常把能完成某一特定功能的一组代码,并且带有名字标记类型叫做函数,在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})