前言
主要是怕自己会忘记,所以摘录了网上一些关于swift3.1新特性的一些记录,总结下自己的看法。
数值类型的failable initialize
Swift为所有的数字类型定义了failable initializer, 当构造失败的时候, 就会返回nil。直接看代码吧,比较直观:
let a = 2.21 let b = Int(a) //结果为2 let c = Int(exactly: a) // 结果为nil let d = 2.0 let e = Int(exactly: d) //结果为2
就是说之前的直接转化是允许丢失精度的,Swift3.1的改动更加的严格了,如果丢失精度会直接返回nil;那么这个有啥作用呢?这么理解吧:如果你是知道需要转化的值的话,比如就是准确的2.11需要取正,那么确实没啥卵用;但是如果你想处理比如Any 可以代表任意类型的数据转化为数字类型的话,如果这个数字不是你期待的值就可以返回nil,你可以多一步的处理逻辑。
Sequence中新添加的两个筛选元素的方法
看下定义
protocol Sequence { // ... /// Returns a subsequence by skipping elements while `predicate` returns /// `true` and returning the remainder. func drop(while predicate: (Self.Iterator.Element) throws -> Bool) rethrows -> Self.SubSequence /// Returns a subsequence containing the initial elements until `predicate` /// returns `false` and skipping the remainder. func prefix(while predicate: (Self.Iterator.Element) throws -> Bool) rethrows -> Self.SubSequence }
这两个方法的含义如下:
prefix(while:): 从数组的第一个元素开始,把符合while闭包条件的元素装进一个数组 A,直到不满足终止,返回数组A; 看下代码:
let arr = ["java","javascript","json","swift","shell","oc"] let a = arr.prefix{$0.hasPrefix("j")} let b = arr.prefix{$0.hasPrefix("s")} print(a) //输出 ["java","javascript","json"],满足含"j"前缀,直到遇到“swift”不满足二终止,返回数组 print(b) //输出 [ ] 。第一个元素就不满足,直接终止返回数组 drop(while:):从第一个元素开始,跳过符合while闭包条件的元素,如果while条件不被满足,则终止判断,并将剩余的元素全部装进数组返回。看代码: let arr = ["java","javascript","json","swift","shell","oc"] let c = arr.drop {$0.hasPrefix("j")} let d = arr.drop {$0.hasPrefix("a")} print(c) //输出 ["swift","shell","oc"],前面三个符合while条件,直接跳过,“swift”开始不满足终止,把剩下的元素装进数字并返回。 print(d) // 输出["java","javascript","json","swift","shell","oc"],因为第一个就不满足直接终止了,剩下的元素就是整个数组。
通过available约束Swift版本
之前的写法:
#if swift(>=3.1) func function1() {} #elseif swift(>=3.0) func function2() {} #endif
现在可以这么写
为了表示某个API从特定版本之后才可用,可以这样:
@available(swift 3.1) func function1() {}
为了表示某个API可用的版本区间,可以这样:
@available(swift, introduced: 3.0, obsoleted: 3.1) func function2() {}
swift3.1针对@available进行了扩展,现在它不仅可以用于限定操作系统,也可以用来区分Swift版本号了。
使用具体类型在extension中约束泛型参数
在Swift3.1之前的版本中,如果想要在Int?类型添加一个方法的话,可能需要这样做:
protocol IntValue { var value: Int { get } } extension Int: IntValue { var value: Int { return self } } extension Optional where Wrapped: IntValue { func something() -> Bool { //do something here } }
在Swift 3.1里,实现起来更加的容易,代码也比较少,也比较容易阅读:
extension Optional where Wrapped == Int { func something() -> Bool { //do something here } }
写起来真是爽。
临时转换成可逃逸的closure
在Swift3.0函数的closure类型参数默认从escaping变成了non-escaping。这很好理解,因为大多数用于函数式编程的closure参数的确都以non-escaping的方式工作。
举个栗子:
func subValue(in array: [Int], with: () -> Int) { let subArray = array.lazy.map { $0 - with() } print(subArray[0]) }
注意,上面代码是不能编译通过的。因为lazy.map()是escaping closure,而with()是默认的non-escaping closure。如果根据编译器的指引,我们可能会在with:的后面添加@escaping:
func subValue(in array: [Int], with:@escaping () -> Int) { let subArray = array.lazy.map { $0 + with() } print(subArray[0]) }
Swift3.1给出了一个临时转换的方法:withoutActuallyEscaping(),我们的方法可以改写成下面这样:
func subValue(in array: [Int], with: () -> Int) { withoutActuallyEscaping(with) { (escapingWith) in let subArray = array.lazy.map { $0 + escapingWith() } print(subArray[0]) } }
withoutActuallyEscaping有两个参数,第一个参数表示转换前的non-escaping closure,第二参数也是一个closure,用来执行需要escaping closure的代码,它也有一个参数,就是转换后的closure。因此,在我们的例子里,escapingWith就是转换后的with。
关于内嵌类型
之前的版本的嵌套:
class A { class B { var value: T init(value: T) { self.value = value; } } }
那么有点歧义 class A 中的T 和class B中的 T是同一个类型吗?为了避开这种歧义,在Swift 3.1里,我们可以把代码改成这样:
class A { class B { var value: T init(value: T) { self.value = value } } }
这样看上去更加的清楚。
希望大家使用的时候可以多多提意见,大家一起进步!
Social Menu