Fork me on GitHub

Swift 相对于 OC 的几个新特性

运算符;

高阶函数;

泛型;

运算符

什么是运算符重载

Swift 中实现运算符重载

双目运算符

  • OC 中我们想把 2CGPoint 相加的时候,由于 CGPoint 是不支持 + 运算符的,所以会有如下的错误信息。

  • 同时我们的解决方案是:

方法1

方法2

但在 Swift 中可以使用运算符重载的方式让 CGPoint 支持 + 运算符。

同理可以添加 + - * / % ... 均可。

前缀运算符

如我们想 CGPoint 取反,即 x -> -xy -> -y

  • 在 OC 中我们通常的实现是如下:

  • 或者封装函数

同上的方法我们可以为 CGPoint 实现此功能。


后缀运算符

  • 同理实现后缀 ++ 功能

自定义运算符

如果常规的运算符已经无法满足我们的需求了,那么是时候自定义我们自己的运算符了。

自定义数目运算符

如果我们现在想实现一种运算符,对 2CGPoint 继续操作时实现的效果是:

1
2
p.x = p1.x+p1.y
p.y = p1.y+p1.x
  • 运算符标识命名为: +++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
// 1、运算符描述
precedencegroup MyPrecedence {
// 优先级,比加法运算高
// higherThan: AdditionPrecedence
// 优先级, 比加法运算低
lowerThan: AdditionPrecedence
// 结合方向:left, right or none
associativity: none
// true = 赋值运算符, false = 非赋值运算符
assignment: false
}
// 2、声明运算符
infix operator +++: MyPrecedence

// 3、实现运算符,+++ 功能就是
func +++(left: CGPoint, right: CGPoint) -> CGPoint {
return CGPoint(x: left.x + right.y, y: left.y + right.x)
}

// 调用 +++
print(CGPoint.init(x: 1, y: 2) +++ CGPoint.init(x: 20, y: 30))

前缀运算符

如果我们现在想实现一种运算符,对 CGPointx * 2y * 4

1
2
p.x = p1.x*2
p.y = p1.y*4
  • 运算符标识命名为: ==+
1
2
3
4
5
prefix operator ==+
prefix func ==+(p: CGPoint) -> CGPoint {
return CGPoint.init(x: p.x*2, y: p.y*4)
}
print(==+CGPoint.init(x: 1, y: 2))

后缀运算符

  • 和前缀运算符同理,但 postfix 来声明是后缀运算符。

高阶函数

什么是高阶函数

一些系统高阶函数的例子

Map

1
2
3
4
5
6
7
8
9
10
11
12
13
14
// 高阶函数
// 1、map
// 对于原始集合里的每一个元素,以一个变换后的元素替换之形成一个新的集合
print([3, 10].map { (num) -> Int in
num*num
})
// 输出 [9, 100]


// 简化版
print([3, 10].map {
$0*$0
})
// 输出 [9, 100]

filter 条件处理

1
2
3
4
5
6
// 2、filter 条件处理
// 对于原始集合里的每一个元素,通过一个自定义的判定来确定是否加入新的集合
print(Array(1...20).filter {
$0 < 10
})
// 输出 [1, 2, 3, 4, 5, 6, 7, 8, 9]

reduce

1
2
3
4
5
6
7
8
// 3、reduce
// 对于原始集合里的每一个元素,作用于当前累积的结果上
// 累积 累加
// Result 结果
print([19, 20].reduce(0) { (result, n) -> Int in
return result+n
})
// 输出 39
  • reduce 的一些例子
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
// 角标总和
print([19, 20].reduce(0) { (result, n) -> Int in
return result+n
})
// 输出 39
print([19, 20].reduce(0) {
return $0+$1
})
// 输出 39


// 连乘
print([19, 20].reduce(1) { (result, n) -> Int in
return result*n
})
// 输出 380

print([19, 20].reduce(1) {
return $0*$1
})
// 输出 380

flatMap

集合的集合处理

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
let arr = [[1,2],[3,4]]
print(arr.flatMap { (nums) -> [Int] in
// 集合筛选 ↓
return nums.map({ (num) -> Int in
// 每一个元素 + 1 组成新的集合
return num+1
})
// 集合筛选 ↑
})
// [2, 3, 4, 5]


// 进一步简化
print(arr.flatMap {$0.map{$0+2}})
// 每一个元素 + 2
// [3, 4, 5, 6]

泛型

什么是泛型

泛型函数

  • 交换 2 个 变量的值,如果有各种类型:Int Double Float NSObject 的时候我们需要为每一种类型都加一个函数,但函数的实现内容完全一样,在 OC 可以使用 id 来解决一些问题,但不太友好。
  • 如果没有泛型就有如下类似的函数
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
func swapTwoInt(_ a: inout Int, _ b: inout Int)  {
(a,b) = (b,a)
}

func swapTwoDouble(_ a: inout Double, _ b: inout Double) {
(a,b) = (b,a)
}

func swapTwoFloat(_ a: inout Float, _ b: inout Float) {
(a,b) = (b,a)
}

func swapTwoObject(_ a: inout NSObject, _ b: inout NSObject) {
(a,b) = (b,a)
}
  • 使用泛型
1
2
3
func swapTwoValues<T>(_ a: inout T, _ b: inout T)  {
(a,b) = (b,a)
}
  • 调用
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
do{
var a = 1
var b = 10
print("\(a)" + " " + "\(b)")
swapTwoValues(&a, &b)
print("\(a)" + " " + "\(b)")
// 输出
// 1 10
// 10 1

}

do{
var a = NSObject.init()
var b = NSObject.init()
print("\(a)" + " " + "\(b)")
swapTwoValues(&a, &b)
print("\(a)" + " " + "\(b)")
}

泛型类型

如果我们要实现一个 Stack,通常 Stack 中的类型是一致的,如果我们要实现存放如下类型的 Stack

  • Int 类型的 Stack
  • Double 类型的 Stack
  • 其他

会有如下的各种类似函数出现

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
struct StackInt {
var items = [Int]()
mutating func push(_ item: Int) -> Int {
items.append(item)
return item
}
mutating func pop() -> Int {
return items.removeLast()
}
}

struct StackDouble {
var items = [Double]()
mutating func push(_ item: Double) -> Double {
items.append(item)
return item
}
mutating func pop() -> Double {
return items.removeLast()
}
}
// ...

其实内部功能基本一致,只是类型不同。

  • 使用泛型类型

就算以后自定义的一些类型也是完全可以使用。

1
2
3
4
5
6
7
8
9
10
struct Stack<Element>{
var items = [Element]()
mutating func push(_ item: Element) -> Element {
items.append(item)
return item
}
mutating func pop() -> Element {
return items.removeLast()
}
}
  • 调用
1
2
3
4
do{
var stack = Stack<Double>.init()
print(stack.push(1.0))
}

泛型约束

通俗的讲就是对上面的泛型加一定的约束限制,满足指定条件才可使用此函数,stack 等。

现在我们要实现一个函数,函数功能是查询数组中是否有指定的元素,如果有就返回 idnex

  • 泛型实现如下:

但会报错,提示 == 不可以用于泛型的 Element,因为系统的 == 的定义如下:

是一个协议,只有遵守了 Equatable 协议的类型才可以使用 == 运算符,就和 OC 中字典的 key 必须是可以哈希的一样。

  • 调整后的函数实现如下:
1
2
3
4
5
6
7
8
func findIndex<Element: Equatable>(_ item: Element, items: [Element]) -> Int? {
for (i, ite) in items.enumerated() {
if item == ite {
return i
}
}
return nil
}

  • 现在让 BMPerson 遵守 Equatable 协议,但同时需实现 == 的实现。

  • 一些系统泛型约束

  • 泛型在 OC 中的一些使用

- END -
扫一扫上面的二维码图案,加我微信

文章作者:梁大红

特别声明:若无特殊声明均为原创,转载请注明,侵权请联系

版权声明:署名-非商业性使用-禁止演绎 4.0 国际