函数
函数基础
在Swift中,函数前面要用func关键字声明,参数写在括号里,并用向右的箭头指向返回值的类型。
func sayHello(name: String?) -> String {
return "Hello " + (name ?? "Guest")
}
var nickName : String? = nil
sayHello(nickName)
nickName = "MC"
sayHello(nickName)
//无参数,无返回值
func printHello1() {
print ("Hello")
}
func printHello2() -> (){
print ("Hello")
}
func printHello3() -> Void{
print ("Hello")
}
使用元组返回多个值
时刻要考虑到函数的参数或返回类型为可选型的情况。
func findMaxAndMin (numbers:[Int]) -> (max:Int , min:Int)? {
guard numbers.count > 0 else {
return nil
}
var minValue = numbers[0]
var maxValue = numbers[0]
for number in numbers {
minValue = minValue < number ? minValue : number
maxValue = maxValue > number ? maxValue : number
}
//return返回的元组里面的各个分量可以不用指明变量名,如果指明必须与函数返回值声明的时候一样。
return (maxValue , minValue)
}
var scores: [Int]? = [202,123,4324,543,123]
scores = scores ?? []
if let result = findMaxAndMin(scores!) {
print("The max score is \(result.max)")
print("The min score is \(result.min)")
}
内部参数名与外部参数名
Swift的函数默认会不显示第一个参数的参数名,但后面的参数会显示出他们的参数名,但这不是绝对的,后面会提到内部参数名和外部参数名的概念。
func sayHelloTo(name: String , greeting: String) -> String {
return "\(greeting),\(name)!"
}
//sayHelloTo("Playground", "Hello") //会报错
sayHelloTo("Playground", greeting: "Hello")
Swift中函数的每一个参数都可以有一个内部参数名和一个外部参数名。外部函数名用于调用函数时显示。没有外部参数名时,原来的参数名默认为内外参数名,当然我们也可以用下划线"_"来让函数被调用时不显示参数名。
func sayHelloTo(name: String , withGreetingWord greeting: String) -> String {
return "\(greeting),\(name)!"
}
sayHelloTo("Playground", withGreetingWord: "Hello")
func mutiply (num1 : Int , _ num2 : Int) -> Int {
return num1 * num2
}
mutiply(2, 3)
内外参数名的使用场景:往往是方面调用者来调用函数,使语义更加明确,苹果官方就是这么做的:
var arr = [1,2,3,4,5]
arr.insert(5, atIndex: 3)
max(2, 3)
补充:下划线"_"目前我们在for-in循环,switch语句和元组中都用到过,这里在函数参数名的时候也用到了。
默认参数值与可变参数
当一个函数有默认参数值时,调用函数的时候会多一种调用方式,即不显示默认参数名称,相应的参数值为默认值。默认参数之间的顺序是可以改变的。默认参数可以放在参数列表的最后,也可以不放在最后,但这时候要注意,当默认参数不在参数列表最后的时候,参数之间的调用顺序是不许改变的。
func sayHelloTo (name: String , withGreetingWord greeting: String = "Hello" , punctuation: String = "!") -> String{
return "\(greeting), \(name)\(punctuation)"
}
sayHelloTo("MC")
sayHelloTo("MC", withGreetingWord: "Hi")
sayHelloTo("MC", withGreetingWord: "Hi", punctuation: "!!!")
sayHelloTo("MC", punctuation: "!!!")
sayHelloTo("MC", punctuation: "!!!" , withGreetingWord: "Hi")
对于一个函数来说,最多只能有一个变长参数类型
func mean( numbers: Double ...) -> Double {
var sum: Double = 0
//将变长参数当做一个数组看待
for number in numbers {
sum += number
}
return sum / Double(numbers.count)
}
mean(2)
mean (2,3,4,5)
常量参数,变量参数与inout参数
在Swift2.2中,函数参数声明为var将会产生一个警告。在Swift3.0中,该语法将被取消。也就是说,对于函数的参数,我们将或者指定为inout类型,或者不指定,默认为let参数。如果需要一个变量参数,则需要在函数体内标注:var num = num。
func toBinary(num: Int) -> String {
var num = num
var res = ""
repeat {
res = String(num%2) + res;
num /= 2
}while num != 0
return res
}
var x = 100
toBinary(x) //1100100
x //x的值并没有被改变
若要在函数内修改完一个值之后,在函数外这个值依旧是被改变的,则要在函数参数类型上表明inout类型,并且在传参数的时候,参数前面要加一个取址符号"&"。
func swapTwoInts(inout a:Int , inout _ b:Int) {
(a , b) = (b , a)
}
var x:Int = 1
var y:Int = 2
swapTwoInts(&x, &y)
x //2
y //1
注意:Swift里的数组,字典,集合等都是按值传递的。
func initArray(inout arr:[Int] , by value:Int) {
for i in 0..<arr.count {
arr[i] = value
}
}
var arr = [1,2,3,4,5]
initArray(&arr, by: 0)
arr //[0,0,0,0,0]
使用函数类型
在Swift中函数也可以当做一个变量,也有相应的类型,即函数型变量。
func add(a:Int , _ b:Int) -> Int {
return a + b
}
let anotherAdd = add //(Int, Int) -> Int类型
anotherAdd(3,4)
//无参数无返回值类型的函数类型可以有下面四种方式表示:
() -> ()
() -> Void
Void -> ()
Void -> Void
下面举一个在实际编程中会用到函数类型的例子:
var arr:[Int] = []
for _ in 0..<100 {
arr.append(random()%1000)
}
arr.sort() //默认从小到大排序
arr.sort(<#T##isOrderedBefore: (Int, Int) -> Bool##(Int, Int) -> Bool#>)
//里面可以传一个(Int, Int) -> Bool类型的函数来告诉数组怎么排序.
//从大到小
func biggerNumberFirst(a:Int , _ b:Int) -> Bool {
return a > b
}
arr.sort(biggerNumberFirst)
//按照字符串的字典序进行排序
func cmpByNumberString(a:Int , _ b:Int) -> Bool {
return String(a) < String(b)
}
arr.sort(cmpByNumberString)
//按照距离500最近的数排序
func near500(a:Int , _ b:Int) -> Bool {
return abs(a - 500) < abs(b - 500)
}
arr.sort(near500)
函数式编程初步
我们以改分系统为例来介绍这个章节的内容:
//常用写法
func changeScores1(inout scores:[Int]){
for (index , score) in scores.enumerate() {
scores[index] = Int(sqrt(Double(score)) * 10)
}
}
func changeScores2(inout scores:[Int]){
for (index , score) in scores.enumerate() {
scores[index] = Int(Double(score) / 150.0 * 100.0)
}
}
var scores1 = [36,61,78,89,99]
changeScores1(&scores1)
var scores2 = [88,101,124,137,150]
changeScores2(&scores2)
//改进写法
func changeScores(inout scores:[Int] , by changeScore: (Int) -> Int){
for (index , score) in scores.enumerate() {
scores[index] = changeScore(score)
}
}
func changeScores1(score:Int) -> Int{
return Int(sqrt(Double(score)) * 10)
}
func changeScores2(score:Int) -> Int{
return Int(Double(score) / 150.0 * 100.0)
}
数组内容的扩展:
//map
changeScores(&scores1, by: changeScores1)
scores1.map(changeScores1)
//返回值可以不仅仅是整型
func isPassOrFail(score: Int) -> String {
return score < 60 ? "Fail" : "Pass"
}
scores1.map(isPassOrFail)
//filter
func fail(score: Int) -> Bool {
return score < 60
}
scores1.filter(fail)
//reduce
var arr = [1,2,3,4,5]
func add(num1:Int , _ num2: Int) -> Int {
return num1 + num2
}
arr.reduce(0, combine: add)
arr.reduce(0, combine: +)
func concatenate(str:String , num: Int) -> String {
return str + String(num) + " "
}
arr.reduce("", combine: concatenate)
返回函数类型与函数嵌套
函数可以作为返回值,并且函数内部可以嵌套函数:
//邮费选择
func tier1MailFeeByWeight(weight: Int) -> Int {
return 1 * weight
}
func tier2MailFeeByWeight(weight: Int) -> Int {
return 3 * weight
}
//总价钱
func feeByUnitPrice(price: Int , weight: Int) -> Int {
func chooseMailFeeCalculationByWeightt(weight: Int) -> (Int) -> Int {
return weight <= 10 ? tier1MailFeeByWeight : tier2MailFeeByWeight
}
let mailFeeByWeight = chooseMailFeeCalculationByWeightt(weight)
return mailFeeByWeight(weight) + price * weight
}
闭包
闭包的基础语法
Swift里面的闭包,跟我们OC里面的block基本是一样的。闭包本质上就是函数。
var arr:[Int] = []
for _ in 0..<100{
arr.append(random()%1000)
}
func biggerNumberFirst(a:Int , _ b:Int) -> Bool {
return a > b
}
arr.sort(biggerNumberFirst)
//使用闭包
arr.sort({ (a:Int,b:Int) -> Bool in
return a > b
})
闭包语法的简化
对于一句话的闭包,我们可以有如下的化简:
arr.sort({ (a:Int,b:Int) -> Bool in
return a > b
})
arr.sort({ (a:Int,b:Int) -> Bool in return a > b})
arr.sort({ a , b in return a > b})
arr.sort({ a , b in a > b})
arr.sort({ $0 > $1})
arr.sort(>)
结尾闭包
当闭包为一个函数要传入的最后一个参数时,闭包可以写在括号的外面。
arr.sort({ a , b in return a > b})
arr.sort(){ a, b in
return a > b
}
arr.sort{ a, b in
return a > b
}
内容捕获
前面我们所用的闭包,都是用来当做函数来使用的,但在一些情况下,闭包是有自己独特的优势的。
//sort里面传入的函数类型是确定的,我们无法传递第三个参数,这时可以利用闭包的内容捕获功能来解决这个问题。
arr.sort(<#T##isOrderedBefore: (Int, Int) -> Bool##(Int, Int) -> Bool#>)
var arr:[Int] = []
for _ in 0..<100{
arr.append(random()%1000)
}
arr.sort{ a, b in
abs(a - 500) < abs(b - 500)
}
var num = 300
arr.sort{ a, b in
abs(a - num) < abs(b - num)
}
闭包和函数是引用类型
之前我们说过,Swift中数组,字典和集合都是值类型,现在我们将接触到Swift中的第一个引用类型。
func runningMetersWithMetersPerDay(metersPerDay: Int) -> () -> Int {
var totalMeters = 0
return {
totalMeters += metersPerDay
return totalMeters
}
}
var planA = runningMetersWithMetersPerDay(2000)
planA() //2000
planA() //4000
planA() //6000
var planB = runningMetersWithMetersPerDay(5000)
planB() //5000
planB() //10000
planB() //15000
var anotherPlan = planB
anotherPlan() //20000
//证明是引用类型
planB() //25000