斯威夫特5.2。所有变更概述

3月底,针对Xcode 11.4发布了Swift 5.2。它改进了错误诊断,依赖性分析并扩展了SwiftPM功能。Habré上已经发布了一些更改的概述,在同一篇文章中,考虑了语言本身的演变以及可能的用法示例。


 

SE-0249 KeyPath功能


快捷方式将keyPath放入函数中,其中输入参数是对象本身,而结果是其属性。

让我们看一个例子。创建一系列简单模型:

struct Model {
    let isHidden: Bool
}
 
let modelArray = [Model(isHidden: true), Model(isHidden: false)]

通过isHidden属性过滤数组。以下是3个示例,它们具有相同的结果:

// 1
let funcIsHidden: (Model) -> Bool = \.isHidden
modelArray.filter(funcIsHidden)
 
// 2
modelArray.filter(\.isHidden as (Model) -> Bool)
 
// 3
modelArray.filter(\.isHidden)

在以下示例中,声明的功能不起作用:

//   
let selfFunc: (Model) -> Model = \.self
modelArray.compactMap(selfFunc)
 
// ERROR: Expression type '(Model) -> Model' is ambiguous without more context
modelArray.compactMap(\.self as (Model) -> Model)
 
// ERROR: Key path value type 'Optional<_>' cannot be converted to contextual type '_'
modelArray.compactMap(\.self)

此外,与keyPath不同,autocomplet不起作用。

使用诸如过滤,映射,归约,排序等功能的数组很方便。

SR-6118下标可能包含默认设置


所有功能参数都可以设置为默认值。创建一个Box结构,其中包含一个元素数组和一个下标函数来访问它们。

struct Box {
    let items: [String]
    
    subscript(_ index: Int = 0) -> String {
        items[index]
    }
}

现在,要访问第一个元素,您可以省略索引:

let box = Box(items: ["laptop, , mobile phone"])
let firstItem = box[] // "laptop"

SR-2189本地功能从外部可见性支持默认参数


在日常实践中,很少使用局部功能。可能难以证明其用途。不过,我承认在某些情况下这可能派上用场。

例如,我们将创建一个函数,在其中描述本地函数:

func getXPosition() {
    func calculateWidth(x: CGFloat = minX) -> CGFloat { ... }
    let minX: CGFloat = 0
    ...
}

作为calculateWidth函数的默认参数,我们可以使用getXPosition函数中的值。

SE-0253将值用作函数


功能类似于@dynamicCallable,允许您将值用作函数。但这是“静态调用”的实现。

实际上,一切都非常简单:要调用函数,您可以将值称为方法。

创建一个播放器结构:

struct Player {
    private(set) var isRunning = false
    
    mutating func callAsFunction() {
        isRunning.toggle()
    }
}

创建一个Player实例,并将其作为函数引用:

var player = Player()
print(player.isRunning) // false
player()
print(player.isRunning) // true

同时,禁止强制转换,因此,将对象作为函数传递:

// ERROR: Cannot convert value of type 'Player' to type '() -> Void' in coercion
let playerAsFunc = player as () -> Void

您可以向类,结构或协议中添加与callAsFunction一样多的方法:

extension Player {
    func callAsFunction(isRunning: Bool = false) throws { ... }
    func callAsFunction() -> Bool { ... }
}

可以在作为数学函数,复杂表达式的值或该值具有一个主导函数的情况下应用。但是,您不应滥用此功能,因为它可能会引起误解。

SR-4206修复了带有通用参数覆盖功能的错误


现在,覆盖该功能,您将无法更改或添加对泛型类型的限制。例如,创建一个CarBuilder类并通过覆盖add方法从其继承:

protocol PowerfullEngine { }
 
class CarBuilder {
  func add<T>(engine: T) {}
}
 
class MercedesBuilder: CarBuilder {
    //  
    override func add<T>(engine: T) {}
    // ERROR: Overridden method 'add' has generic signature <T where T : PowerfullEngine> which is incompatible with base method's generic signature <T>; expected generic signature to be <T>
    override func add<T: PowerfullEngine>(engine: T) {}
}

SR-11298扩展无类限制的协议会继承此限制


在“自我”限制的情况下,扩展程序将应用该限制。

例如,创建具有类限制的Menu和extension协议:

protocol Menu {}
 
class SideMenu: Menu {
  var sectionHeight = 0
}
 
extension Menu where Self: SideMenu {
  var menuHeight: Int {
    get { sectionHeight * 20 }
    set { sectionHeight = newValue / 20 }
  }
}

同时,设置程序是非突变的,就像协议具有类限制一样。

SR-11429带有标签的功能的转换


现在,删除了用于键入标签的转换功能时。因此,您可以使用标签强制转换功能。以前,此功能仅在没有标签的功能中起作用:

func setX(x: Int) {}
(setX as (Int) -> Void)(5)

但是,将不会保存默认值:

func setPoint(x: Int, y: Int = 0) {}
(setPoint as (Int, Int) -> Void)(5, 1)

这也适用于泛型,因此此代码不再有效。

typealias Point<T> = T
func set(x: Int) {}
 
//  
(set as Point)(5) 
 
// ERROR: Extraneous argument label 'x:' in call
(set as Point)(x: 5) 

SR-11841在惰性集合中按预期顺序调用了filter(_ :)函数


创建一个惰性集合并调用count方法:

let lazyArray = [0]
    .lazy
    .filter { _ in print("A"); return true }
    .filter { _ in print("B"); return true }
 
//  A B
_ = lazyArray.count

之前,通话结果相反:BA。

SR-2790现在,许多UnsafePointer / UnsafeBufferPointer系列的类型初始化器发出警告


该限制适用于在函数调用之外不存在的字符串,数组和inout参数。

创建一个在初始化期间将UnsafePointer作为参数的结构:

struct Game {
    let info: UnsafePointer<Int8>
}
 
func createGame() {
    var i: Int8 = 0
    
    // WARNING: Initialization of 'UnsafePointer<Int8>' results in a dangling pointer
    _ = Game(info: .init(&i))
    
    // WARNING: Passing '[Int8]' to parameter, but argument 'character' should be a pointer that outlives the call to 'init(character:)'
    _ = Game(info: [1, 2])
    
    // WARNING: Passing 'String' to parameter, but argument 'character' should be a pointer that outlives the call to 'init(character:)
    _ = Game(info: "")
}

此版本中有9处更改,但是它们确实带来了新功能。我认为当前使用最多的是KeyPath函数。

我们期待下一个版本。显然,它将在Windows上支持Swift,并且会出现一些有趣的功能,例如在转义闭包中使用self而不通过self访问*(SE-0269)和泛型SE-0267)的功能将会扩展

资源

All Articles