美文网首页
iOS开发 -- Swift之函数与闭包(七)

iOS开发 -- Swift之函数与闭包(七)

作者: Sorphiean | 来源:发表于2016-09-18 14:33 被阅读0次

    函数

    函数基础

    在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
    

    相关文章

      网友评论

          本文标题:iOS开发 -- Swift之函数与闭包(七)

          本文链接:https://www.haomeiwen.com/subject/vixgettx.html