这一小段讲的主要是泛型的重载
相关知识点git
/// 泛型打印view的相关信息
///
/// - Parameter view: view
func log<View: UIView>(_ view: View) {
print("It's a \(type(of: view)), frame: \(view.frame)")
}
///对泛型的重写
func log(_ view: UILabel) {
let text = view.text ?? "(empty)"
print("It's a label, text: \(text)")
}
let label = UILabel(frame: .zero)
label.text = "liaoworking is handsome~~"
let button = UIButton(frame: CGRect(x: 0, y: 0, width: 100, height: 101))
log(label) //It's a label, text: liaoworking is handsome~~
log(button) //It's a UIButton, frame: (0.0, 0.0, 100.0, 101.0)
复制代码
上面这个demo没毛病对吧,只要咱们重载了一个泛型方法, 在打印对于的类型时就调用这个方法。 那咱们看看上面方法的下面的使用场景
github
let views = [label, button] // Type of views is [UIView] for view in views {
for view in views {
log(view)
}
/*
It's a UILabel, frame: (20.0, 20.0, 200.0, 32.0)
It's a UIButton, frame: (0.0, 0.0, 100.0, 50.0)
*/
复制代码
咦~为嘛在for循环中就没法去区分方法了
??? 手动黑人问号脸。swift
缘由:泛型的重载在编译时期
就肯定的。并非在runtime时候动态肯定。 就会有上面的差别。数组
幂运算
的方法precedencegroup tt{//优先级定义
associativity: left //结合方向
higherThan: MultiplicationPrecedence //高于乘法类型
}
infix operator **: tt
func **(lhs: Double, rhs: Double) -> Double {
return pow(lhs, rhs)
}
func **(lhs: Float, rhs: Float) -> Float {
return powf(lhs, rhs)
}
2*2.0**3.0
复制代码
func **<i: SignedInteger>(lhs: i, rhs: i) -> i {
let result = Double(lhs.max) ** Double(rhs.max)
return numericCast(IntMax(result))
}
2**3 ///Error: Ambiguous use of operator
复制代码
可在实际编译过程当中却编译不过闭包
缘由:
对于重载运算符,编译器会使用非泛型
版本,不考虑泛型版本函数
解决:
至少将一个参数显示的声明
为Int类型,或者将返回值声明
为Int类型便可性能
let intResult: Int = 2 ** 3 //8
复制代码
这种编译器的行为只是对运算符
生效,swift团队对于性能上的考量
选择了这种能够下降类型检查器的复杂度的方案。ui
子集
swift标准库中有一个方法isSubSet
提供了这功能,但只是知足于Set这种知足了SetAlgebra
协议的类型。spa
咱们本身去实现这个功能时注意函数的复杂度,for循环遍历会使复杂度变成O(m * n)
.code
若是序列元素知足Hashable咱们能够经过Set(array)
数组转化为Set,再去用isSubSet去得到结果。
书中给出的最优解决方案是以下
///不须要是同一种类型 只须要other遵照Sequence的任意类型就能够了,其复杂度也是成线性增加。
extension Sequence where Iterator.Element: Hashable {//泛型版本
func isSubset<S: Sequence>(of other: S) -> Bool
where S.Iterator.Element == Iterator.Element {
let otherSet = Set(other)
for element in self {
guard otherSet.contains(element) else {
return false
}
}
return true
}
复制代码
这样咱们写的函数就有更多的可能性
,能够传入一个数字的countableRange来进行检查
[5,4,3].isSubSet(of:1...10)//true
复制代码
函数的封装
有很大的启发。针对于上面的demo咱们二次引伸
: 让isSubset针对于不是Equatable
的类型也适用, 咱们能够传一个返回值是bool的函数来代表元素是否相等。 swift标准库中的contains
方法就是这么作的 其具体使用以下:
let isEven = {$0 % 2 == 0}
(0..<5).contains(where:isEven) //true
[1,3,5,7,9].contains(where:isEven) == false
复制代码
extension Sequence {
func isSubset<S: Sequence>(of other: S,
by areEquivalent: (Iterator.Element, S.Iterator.Element) -> Bool)
-> Bool {
for element in self {
guard other.contains(where: {areEquivalent(element, $0)}) else{return false}
}
return true
}
}
复制代码
只要你提供闭包可以处理的比较操做
,两个序列的元素就算不是同种类型
的也能够进行对比。
let ints = [1,2]
let strings = ["1","2","3"]
ints.isSubset(of:Strings) { String($0) == $1 } //true
复制代码
这一节知识点有点繁琐。 不必一次性弄懂,多体会慢慢在实际项目中运用就能够啦~