【Swift】基础语法(3) —— 函数 、方法和闭包

函数

函数是用来完成特定任务的独立的代码块。

定义

定义函数使用关键字func,指定一个或多个输入参数和一个返回值类型。格式如下:

func 方法名(参数1:参数类型1,参数2:参数类型2) -> 返回值类型
{
   // ……
   return ...
}

元组作为函数返回值

可以用元组(tuple)类型让多个值作为一个复合值从函数中返回。

如果不确定返回的元组一定不为nil,那么可以返回一个可选的元组类型,如:

func minMax(array: [Int]) -> (min: Int, max: 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 (currentMin, currentMax)
}

可选元组类型如(Int, Int)?与元组包含可选类型如(Int?, Int?)是不同的.可选的元组类型,整个元组是可选的,而不只是元组中的每个元素值。

外部参数名

可以在局部参数名前指定外部参数名,中间以空格分隔,外部参数名用于在函数调用时传递给函数的参数,如:

func pow(firstArg a: Int, secondArg b: Int) -> Int {
   var res = a
   for _ in 1..<b {
      res = res * a
   }
   print(res)
   return res
}
pow(firstArg:5, secondArg:3)

如果提供了外部参数名,那么函数在被调用时,必须使用外部参数名,函数内部则可以使用局部参数名。

可变参数

可变参数可以接受零个或多个值。

可变参数通过在变量类型名后面加入(…)的方式来定义,如:

func vari<N>(members: N...){
    for i in members {
        print(i)
    }
}
vari(members: 4,3,5)
vari(members: 4.5, 3.1, 5.6)
vari(members: "Google", "Baidu", "Runoob")

函数类型作为参数类型

函数类型由函数的参数类型和返回类型组成,可以看成是一个特殊的类型。如
(Int, Int) -> Int

将函数作为参数传递给另外一个函数:

func sum(a: Int, b: Int) -> Int {
    return a + b
}
func another(addition: (Int, Int) -> Int, a: Int, b: Int) {
    print("输出结果: \(addition(a, b))")
}
another(addition: sum, a: 10, b: 20)

函数类型作为返回类型 及 函数嵌套

将函数作为返回值将会得到一个函数类型的值,可以通过调用来获取这个返回函数的返回值,如:

// 返回值的类型为 () -> Int
func calcDecrement(forDecrement total: Int) -> () -> Int {
   var overallDecrement = 0
   // 函数内部可以定义新的函数,即函数嵌套
   func decrementer() -> Int {
      overallDecrement -= total
      return overallDecrement
   }
   return decrementer
}
let decrem = calcDecrement(forDecrement: 30)
// 执行返回的函数,输出值为 -30
print(decrem())

方法

方法是与某些特定类型相关联的函数,在OC中,只有类才能定义方。但是在Swift中,可以将方法定义在类、结构体和枚举上。

实例方法

实例方法是属于某个特定类、结构体或者枚举类型实例的方法。

实例方法提供以下方法:

  • 可以访问和修改实例属性
  • 提供与实例目的相关的功能

实例方法要写在它所属的类型的前后大括号({})之间。

实例方法能够隐式访问它所属类型的所有的其他实例方法和属性。

实例方法只能被它所属的类的某个特定实例调用。

实例方法不能脱离于现存的实例而被调用。

(类似于OC中的实例方法)

例如:

class calculations {
    let a: Int
    let b: Int
    let res: Int
    
    init(a: Int, b: Int) {
        //实例方法的某个参数名称与实例属性名称相同的时,参数名称优先,这时需要用self来区分参数名称和属性名称
        self.a = a
        self.b = b
        res = a + b
        print("Self 内: \(res)")
    }
    
    func tot(c: Int) -> Int {
        return res - c
    }
    
    func result() {
        print("结果为: \(tot(c: 20))")
    }
}
// 调用
let pri = calculations(a: 600, b: 300)
pri.result()

结构体

struct Teacher {
    var name = "lilei"
    var age = 0
    
    // 方法定义时加上了mutating关键字,允许修改属性
    mutating func changeName() {
        name = "hanmeimei"
    }
}
// 调用
var teacher = Teacher()
print(teacher.name)   //lilei
teacher.changeName()
print(teacher.name)    //hanmeimei

枚举

enum Color{
    case red
    case yellow
    case green
    
    // 方法定义时加上了mutating关键字,允许修改属性
    mutating func changeColor() {
        switch self {
        case .red:
            self = .yellow
        case .yellow:
            self = .green
        case .green:
            self = .red
        }
    }
}
// 调用
var color = Color.red
print(color)    //red
color.changeColor()
print(color)    //yellow

类型(类)方法

类型方法可以对应到OC中的类方法进行理解。

结构体和枚举的类型方法,在方法的func关键字之前加上关键字static。

类的类型方法,在方法的func关键字之前加上关键字class,子类可以重写父类的实现方法。

例如:

class Student: NSObject {
    static var name = "hanmeimei"
    class func sayHI(name :String) {
        print("hello \(name),I am \(self.name)")
    }
}
// 调用
Student.sayHI(name: "lilei")

结构体

struct Teacher {
    static var name = "lilei"
    static func changeName() {
        name = "hanmeimei"
    }
}
// 调用
print(Teacher.name)     //lilei
Teacher.changeName()
print(Teacher.name)     //hanmeimei

闭包

闭包(Closures)是自包含的功能代码块,可以在代码中使用或者用来作为参数传值。
类似于OC中的代码块(blocks)。

Swift中的闭包相对于代码块有很多优化的地方:

1、根据上下文推断参数和返回值类型

2、从单行表达式闭包中隐式返回(也就是闭包体只有一行代码,可以省略return)

3、可以使用简化参数名,如$0, $1(从0开始,表示第i个参数…)

4、提供了尾随闭包语法(Trailing closure syntax)

语法

闭包的语法形式如下:

{(参数1:参数类型1,参数2:参数类型2...) -> 返回值类型 in
   ...//执行代码
}

例:

let divide = {(val1: Int, val2: Int) -> Int in 
   return val1 / val2 
}
let result = divide(200, 20)
print (result)

闭包表达式

闭包表达式是一种利用简洁语法构建内联闭包的方式,例如:

OC中的数组排序sortedArrayUsingComparator:代码如下:

[array sortedArrayUsingComparator:^NSComparisonResult(id obj1, id obj2) {
   // 排序代码
}];

对应的,swift中也提供了sorted(by:)的方法,例如:

let names = ["AT", "AE", "D", "S", "BE"]
// 使用普通函数(或内嵌函数)提供排序功能,闭包函数类型需为(String, String) -> Bool。
func backwards(s1: String, s2: String) -> Bool {
    return s1 > s2
}
var reversed = names.sorted(by: backwards)

参数名称缩写

可以直接通过$0,$1,$2来顺序调用闭包的参数,例如:

var reversed = names.sorted( by: { $0 > $1 } )

运算符函数

String类型定义了关于大于号>的字符串实现,其函数类型与sorted(by:)所传的函数类型一致,因此可以直接传>作为参数:

var reversed = names.sorted(by: >)

尾随闭包

尾随闭包是调用时书写在函数括号之后的闭包表达式,它将其作为最后一个参数传入调用的方法中,例如:

// sorted()中没有传递参数,{ $0 > $1 }闭包将作为最后一个参数传入sorted方法中
// 等同于names.sorted( by: { $0 > $1 } )
var reversed = names.sorted() { $0 > $1 }

捕获值

闭包可以在其定义的上下文中捕获常量或变量。

即使定义这些常量和变量的原域已经不存在,闭包仍然可以在闭包函数体内引用和修改这些值(有点类似于OC中的block,会捕获上下文中有用到的对象)。

例如:

func makeIncrementor(forIncrement amount: Int) -> () -> Int {
    var runningTotal = 0
    func incrementor() -> Int {
        runningTotal += amount
        return runningTotal
    }
    return incrementor
}
// 返回的incrementByTen实际上是函数 incrementor,它会捕获变量runningTotal
let incrementByTen = makeIncrementor(forIncrement: 10)
// 执行时,runningTotal = 0,返回的值为10
print(incrementByTen())
// 执行时,runningTotal = 10,返回的值为20
print(incrementByTen())
// 闭包是引用类型, 即无论将其赋值给变量还是常量,它的值都指向的是闭包的引用(可以看做是方法的地址),因此两个值会指向同一个闭包:
let alsoIncrementByTen = incrementByTen
// 执行时,runningTotal = 20,返回的值为30
print(alsoIncrementByTen())

参考文章

Swift 函数

Swift 方法

Swift 闭包

https://juejin.im/post/5e37a1526fb9a02fb75d6cff

「点点赞赏,手留余香」

    还没有人赞赏,快来当第一个赞赏的人吧!
0 条回复 A 作者 M 管理员
    所有的伟大,都源于一个勇敢的开始!
欢迎您,新朋友,感谢参与互动!欢迎您 {{author}},您在本站有{{commentsCount}}条评论