前言
也可以关注我的个人博客
主要是怕自己会忘记,所以摘录了网上一些关于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<T> {
class B<T> {
var value: T
init(value: T) {
self.value = value;
}
}
}
那么有点歧义 class A 中的T 和class B中的 T是同一个类型吗?为了避开这种歧义,在Swift 3.1里,我们可以把代码改成这样:
class A<T> {
class B {
var value: T
init(value: T) {
self.value = value
}
}
}
这样看上去更加的清楚。
希望大家使用的时候可以多多提意见,大家一起进步!
大家可以关注我的个人博客