Swift高阶语法

2021-07-01  本文已影响0人  鄭经仁

1.数组元素类型转换map

//swift为函数的参数自动提供简写形式,$0代表第一个参数,$1代表第二个参数
let array = ["1", "2", "3"]
let str1 = array.map({ "\($0)"}) //数组每个元素转成String类型
//字符串数组转NSInteger类型数组
let array1 = array.map { (obj) -> NSInteger in
    return NSInteger(obj) ?? 0
}
//NSInteger类型数组转字符串数组
let array2 = array1.map { (obj) -> String in
    return String(obj)
}
print("array1: \(array1)")
print("array2: \(array2)")
//str1 ["1", "2", "3"]
//array1: [1, 2, 3]
//array2: ["1", "2", "3"]
举例 ,年月日字符串分割成数组,这时数组是Substring类型数组,需要定义Substring数组,否则无法转换
var timeArray = [Substring]()
timeArray = (model.functionTitle?.split(separator: "-"))!
guard timeArray.count > 0 else {
    return
}
//let dataArray = timeArray.map { (obj) -> NSInteger in
 //   return NSInteger(obj) ?? 0
//}
//可以省略写法
let dataArray = timeArray.map {return NSInteger($0) ?? 0}
flatMap, 功能跟map类似; 区别是flatMap会过滤nil元素, 并解包Optional。
flatMap还可以将多维数组转换为一维数组,对于N维数组, map函数仍然返回N维数组。
let array = [[1, 2, 3],[1, 2, 3],[1, 2, 3]]
let arrret = array.flatMap{$0}
let arrret1 = array.map{$0}
print(arrret)
print(arrret1)
//[1, 2, 3, 1, 2, 3, 1, 2, 3]
//[[1, 2, 3], [1, 2, 3], [1, 2, 3]]
filter函数, 顾名思义就是过滤出符合条件的元素。
let array = [1, 2, 3]
let resultArray = array.filter { return $0 > 1 }
print(resultArray)
//[2, 3]

2.匿名函数

函数可以使用func关键字创建,也可以使用{ }(花括号)来创建,这种方法可以称为匿名函数
//第一种写法
func doublerTest(i: Int) -> Int {
    return i * 2
}
[1,2,3,4].map(doublerTest)

//第二种写法 (匿名函数)
let doublerTest1 = {(i: Int) -> Int in
    return i * 2
}
[1,2,3,4].map(doublerTest1)
上述这两种出了传参的处理上略有不同,其实是完全等价的。

3.闭包表达式

1.正常函数
//正常函数
func fn(v1:Int,v2:Int) -> Int {
     v1+v2
}
//闭包

//闭包写法
{
    (参数) -> 返回值类型 in
     函数体代码
}
//闭包调用写法
var fn1 = {
    (v1:Int,v2:Int) -> Int in
    return v1 + v2
}

//闭包调用简写1
var fn2 = {
    (v1:Int,v2:Int) in
     v1 + v2
}

print(fn(v1: 10, v2: 12))
print(fn1(10,20))
print(fn2(10,20))
2.函数嵌套
//正常函数
func sum(v1:Int,v2:Int,fn:(Int,Int) -> Int ) {
    print(fn(v1, v2))
}
//正常函数
func fn(v1:Int,v2:Int) -> Int {
     v1+v2
}

//闭包调用简写1
sum(v1: 10, v2: 20,fn: {
    (v1:Int,v2:Int)  -> Int in
    return v1+v2
})

//闭包调用简写2
sum(v1: 10, v2: 20,fn: {
    (v1:Int,v2:Int) in
    return v1+v2
})

//闭包调用简写3
sum(v1: 10, v2: 20,fn: {
    (v1,v2) in
    return v1+v2
})

//闭包调用简写4
sum(v1: 10, v2: 20,fn: {
    v1,v2 in
    return v1+v2
})

//闭包调用简写5
sum(v1: 10, v2: 20,fn: {
    v1,v2 in
    v1+v2
})

//闭包调用简写6
sum(v1: 10, v2: 20,fn: {
   $0 + $1
})

//尾随闭包写法
//闭包调用简写7
sum(v1: 10, v2: 20) { v1, v2 in
    v1 + v2
}

//闭包调用简写8 
sum(v1: 10, v2: 20) { $0 + $1
}

最完美写法尾随闭包
//尾随闭包调用简写8
sum(v1: 10, v2: 20) { $0 + $1
}
3.尾随闭包
1.如果很长的闭包表达式作为函数的最后一个实参(必须最后一个实参),使用尾随闭包可以增强函数的可读性,尾随闭包是一个被书写在函数调用括号外面(后面)的闭包表达式,如上闭包调用简写8
2.如果闭包表达式作为函数的唯一实参,并且使用了尾随闭包的语法,那就不需要在函数后面写圆括号
//正常函数
func sum(fn:(Int,Int) -> Int ) {
    print(fn(1, 2))
}

func fn(v1:Int,v2:Int) -> Int {
     v1+v2
}

//调用简写1
sum { v1, v2 in
    v1+v2
}
//调用简写2
sum {$0+$1}

4.闭包(闭包和闭包表达式是两种概念)

一个函数和它所捕获的变量\常量环境组合起来,称为闭包
一般指定义在函数内部的函数
一般它捕获的是外层函数的局部变量\函数
//定义Fn类型是参数int返回int的方法
typealias Fn = (Int) -> Int

func getFn() -> Fn{
    //局部变量,
    var num = 0
    func plus(i: Int) -> Int {
        num += i
        return num
    }
    return plus
}//返回的plus和num形成了闭包

//上面方法等同下面方法
func getFn1() -> Fn{
    //局部变量
    var num = 0
    return {
        num += $0
        return num
    }
}//返回的plus和num形成了闭包
let fn = getFn()//这就是闭包,可以放放局部变量、常量

print(fn(1))
print(fn(2))
print(fn(3))
print(fn(4))
//返回1 3 6 10
let fn1 = getFn()//这就是闭包,可以放放局部变量、常量
print(fn1(1))
print(fn1(3))
//返回1 4
如果不初始化方法局部变量放在堆空间,所以不会销毁,如果初始化会销毁对空间
闭包可以想象成一个类的实例对象,内存在堆空间
当需要一个方法返回一个方法对象给别人时,就需要用到闭包

5.Error处理

1.返回类型后面加? 可选类型
func divide(num1:Int,num2:Int) -> Int? {
    if num2 == 0 {
        return nil
    }
    return num1/num2
}
print(divide(num1: 1, num2: -1))
2.do try-catch
//1.创建自定义的异常枚举,并遵守 Error 协议:
enum someError: Error{
    case illegalArg(String)
    case ourtOfBounds(Int,Int)
}
//2.主要涉及关键字 throws、throw 的用法,代码形式如下:
func divide(num1:Int,num2:Int) throws-> Int {
    if num2 == 0 {
        throw someError.illegalArg("0不能作为除数")
    }
    return num1/num2
}
3.在 do 中 try 可以抛出错误的方法、并调用继续执行的方法;在 catch 中处理响应的错误,并且 catch 的写法多种多样(可以在多个 catch 中分别 捕获不同错误,也可以在 catch 中 通过 switch case 分别进行捕获),所有捕获的情况一定要写全。
func test() {
    do {
        print(try divide(num1: 1, num2: 0))
    } catch let someError.illegalArg(msg) {
        print("参数异常",msg)
    } catch let someError.ourtOfBounds(size ,index){
        print("内存溢出","size\(size)","index\(index)")
    } catch {
        print("其他错误")
    }
}
3.特殊关键字 try!、try?
try!、try?调用可能抛出Error的函数,这样就不用去处理Error(try?、try!修饰的方法里还是需要做判断处理抛出异常)
若确定可能抛出异常的某方法本次不抛出异常,则可前置 try! 来调用,可一旦这段代码抛出了一个异常,则会引起运行时错误。
try? 代表方法可能抛出错,也可能没错,如果发生错误,那么返回nil,如果没有发生错误,系统会把数据包装成一个可选类型的值返回。
enum someError: Error{
    case illegalArg(String)
    case ourtOfBounds(Int,Int)
}
//2.主要涉及关键字 throws、throw 的用法,代码形式如下:
func divide(num1:Int,num2:Int) throws-> Int {
    if num2 == 0 {
        throw someError.illegalArg("0不能作为除数")
    }
    return num1/num2
}
func test() {
    var result1 = try? divide(num1: 10, num2: 10)
    var result2 = try? divide(num1: 10, num2: 0)
    var result3 = try! divide(num1: 10, num2: 10)
}
下面两个定义是等价的
var a = try? divide(num1: 10, num2: 0)
var b: Int?
do {
    try b = divide(num1: 10, num2: 0)
} catch {
    b = nil
}
4. rethrows表名:函数本身不回抛出错误,但调用闭包参数抛出错误,那么它会将参数向上抛
5.defer语句:用来定义以任何方式(抛出错误、return等)离开代码块之前必须执行的代码,defer语句讲延迟至当前作用域结束之前执行
enum someError: Error{
    case illegalArg(String)
    case ourtOfBounds(Int,Int)
}
func divide(num1:Int,num2:Int) throws-> Int {
    if num2 == 0 {
        throw someError.illegalArg("0不能作为除数")
    }
    print(num1/num2)
    return num1/num2
}

func result()  {
    defer {
        print("必须执行")
    }
    try? divide(num1: 10, num2: 0)
}

6.泛型

泛型是可以将类型参数化,提高代码复用率,减少代码量。可以用在类、结构体、函数、枚举
//元素交换方法
func swapValues<T>(_ a: inout T,_ b:inout T )  {
    (a,b) = (b,a)
}
var a = 10
var b = 20
swapValues(&a, &b)

var c = 10.05
var d = 20.05
swapValues(&c, &d)

7.关联类型

关联类型用在协议中,协议可以又多个关联类型
protocol Stackable {
    associatedtype Element //关联类型
    associatedtype Element1 //关联类型
    associatedtype Element2 //关联类型
    mutating func push(_ element: Element)
    mutating func pop() -> Element
    func top() -> Element
    func size() -> Int
}


class strungStack: Stackable {

    typealias Element1 = Int

    typealias Element2 = Double

    typealias Element = String///给关联类型定义真实类型

    func push(_ element: Element) {

    }

    func pop() -> Element {
        return "111"
    }

    func top() -> Element {
        return "111"
    }

    func size() -> Int {
        return 111
    }

}
上一篇下一篇

猜你喜欢

热点阅读