Swift4.0 新特性----语法改进

Swift4.0 新特性----语法改进,第1张

概述注:文章转自这里 1.extension 中可以访问 private 的属性 看下面的代码: struct Date: Equatable, Comparable { private let secondsSinceReferenceDate: Double static func ==(lhs: Date, rhs: Date) -> Bool { return

注:文章转自这里


1.extension 中可以访问 private 的属性
看下面的代码:
struct Date: Equatable,Comparable {    private let secondsSinceReferenceDate: Double    static func ==(lhs: Date,rhs: Date) -> Bool {        return lhs.secondsSinceReferenceDate == rhs.secondsSinceReferenceDate    }    static func <(lhs: Date,rhs: Date) -> Bool {        return lhs.secondsSinceReferenceDate < rhs.secondsSinceReferenceDate    }}

该代码定义了一个 Date 结构体,并实现 Equatable 和 Comparable 协议。为了让代码更清晰,可读性更好,一般会把对协议的实现放在单独的 extension 中,这也是一种非常符合 Swift 风格的写法,如下:

struct Date {    private let secondsSinceReferenceDate: Double}extension Date: Equatable {    static func ==(lhs: Date,rhs: Date) -> Bool {        return lhs.secondsSinceReferenceDate == rhs.secondsSinceReferenceDate    }}extension Date: Comparable {    static func <(lhs: Date,rhs: Date) -> Bool {        return lhs.secondsSinceReferenceDate < rhs.secondsSinceReferenceDate    }}

但是在 Swift 3 中,编译就报错了,因为 extension 中无法获取到 secondsSinceReferenceDate 属性,因为它是 private 的。于是在 Swift 3 中,必须把 private 改为 fileprivate。
struct Date {    fileprivate let secondsSinceReferenceDate: Double}

但是如果用 fileprivate,属性的作用域就会比我们需要的更大,可能会不小心造成属性的滥用。

在 Swift 4 中,private 的属性的作用域扩大到了 extension 中,并且被限定在了 struct 和 extension 内部,这样就不需要再改成 fileprivate 了,这是最好的结果。


2.类型和协议的组合类型
看下面的代码:
protocol Shakeable {    func shake()}extension UIbutton: Shakeable { /* ... */ }extension UiSlider: Shakeable { /* ... */ }func shakeEm(controls: [???]) {    for control in controls where control.isEnabled {}    control.shake()}

在 Swift 3 中,[]里的 ??? 应该写什么呢?如果写 UIControl,那么 control.shake() 就会报错;如果写 Shakeable,那么 control.isEnabled 就会报错。其实我们也可以这样写:
func shakeEm(controls: [UIControl]) {    for control in controls where control.isEnabled {        if control is Shakeable {            (control as! Shakeable).shake()        }    }}

这样写虽然可以跑通了,但是很丑陋。
在 Swift 4 中,可以把类型和协议用 & 组合在一起作为一个类型使用,就可以像下面这样写了:

protocol Shakeable {    func shake()}extension UIbutton: Shakeable { /* ... */ }extension UiSlider: Shakeable { /* ... */ }func shakeEm(controls: [UIControl & Shakeable]) {    for control in controls where control.isEnabled {        control.shake()    }}

把它声明为了 UIControl & Shakeable 类型。OK,圆满解决。
另外,iOS SDK 中的 API 也用这个特性做了优化,例如:
// Objective-C API@interface NSCandIDateListtouchbarItem<CandIDateType> : NStouchbarItem@property (nullable,weak) NSVIEw <NSTextinputClIEnt> *clIEnt;@end

这个 API 的 Objective-C 版本是没有问题的,可以知道 clIEnt 属性既是一个 NSVIEw,又符合 NSTextinputClIEnt 协议。然而它对应的 Swift 3 版本仅仅是一个 NSVIEw 类型:
class NSCandIDateListtouchbarItem<CandIDateType: AnyObject> : NStouchbarItem {    var clIEnt: NSVIEw?}

在 Swift 4 中,这类 API 做了优化,类型的声明就更加严谨,改成了:

class NSCandIDateListtouchbarItem<CandIDateType: AnyObject> : NStouchbarItem {    var clIEnt: (NSVIEw & NSTextinputClIEnt)?}

3.Associated Type 可以追加 Where 约束语句
在 Swift 4 中可以在 associatedtype 后面声明的类型后追加 where 语句:
associatedtype Element where <xxx>

看下面是 Swift 4 标准库中 Sequence 中 Element 的声明:

protocol Sequence {    associatedtype Element where Self.Element == Self.Iterator.Element    // ...}

它限定了 Sequence 中 Element 这个类型必须和 Iterator.Element 的类型一致。
通过 where 语句可以对类型添加更多的约束,使其更严谨,避免在使用这个类型时做多余的类型判断。


4.新的 Key Paths 语法
先来看看 Swift 3 中 Key Paths 的写法:
@objcmembers class KID: NSObject {    dynamic var nickname: String = ""    dynamic var age: Double = 0.0    dynamic var frIEnds: [KID] = []}var ben = KID(nickname: "Benji",age: 5.5)let kIDsnameKeyPath = #keyPath(KID.nickname)let name = ben.valueForKeyPath(kIDsnameKeyPath)ben.setValue("Ben",forKeyPath: kIDsnameKeyPath)

Swift 4 中创建一个 KeyPath 用 \ 作为开头:
\KID.nickname

当编译器可以推导出类型时,可以省略基础类型部分:

\.nickname

上面的代码在 Swift 4 中就可以这样写:
struct KID {    var nickname: String = ""    var age: Double = 0.0    var frIEnds: [KID] = []}var ben = KID(nickname: "Benji",age: 8,frIEnds: [])let name = ben[keyPath: \KID.nickname]ben[keyPath: \KID.nickname] = "BigBen"

相比 Swift 3,Swift 4 的 Key Paths 具有以下优势: 1) 类型可以定义为 class、struct
2) 定义类型时无需加上 @objcmembers、dynamic 等关键字
3) 性能更好
4) 类型安全和类型推断,例如 ben.valueForKeyPath(kIDsnameKeyPath) 返回的类型是 Any,ben[keyPath: \KID.nickname] 直接返回 String 类型
5) 可以在所有值类型上使用

5.下标支持泛型
有时候会写一些数据容器,Swift 支持通过下标来读写容器中的数据,但是如果容器类中的数据类型定义为泛型,以前的下标语法就只能返回 Any,在取出值后需要用 as? 来转换类型。Swift 4 定义下标也可以使用泛型了。
struct GenericDictionary<Key: Hashable,Value> {    private var data: [Key: Value]        init(data: [Key: Value]) {        self.data = data    }        subscript<T>(key: Key) -> T? {        return data[key] as? T    }}let dictionary = GenericDictionary(data: ["name": "Xiaoming"])let name: String? = dictionary["name"] // 不需要再写 as? String
总结

以上是内存溢出为你收集整理的Swift4.0 新特性----语法改进全部内容,希望文章能够帮你解决Swift4.0 新特性----语法改进所遇到的程序开发问题。

如果觉得内存溢出网站内容还不错,欢迎将内存溢出网站推荐给程序员好友。

欢迎分享,转载请注明来源:内存溢出

原文地址: https://outofmemory.cn/web/1059392.html

(0)
打赏 微信扫一扫 微信扫一扫 支付宝扫一扫 支付宝扫一扫
上一篇 2022-05-25
下一篇 2022-05-25

发表评论

登录后才能评论

评论列表(0条)

保存