Cepat 5.2. Ikhtisar semua perubahan

Pada akhir Maret, Swift 5.2 dirilis untuk Xcode 11.4. Ini telah meningkatkan diagnosis kesalahan, analisis ketergantungan, dan fungsionalitas SwiftPM yang diperluas. Tinjauan beberapa perubahan telah dipublikasikan di Habré , dalam artikel yang sama evolusi bahasa itu sendiri dengan contoh-contoh penggunaan yang mungkin dipertimbangkan.


 

SE-0249 KeyPath sebagai fungsi


Shortcut menempatkan keyPath ke dalam suatu fungsi, di mana parameter input adalah objek itu sendiri, dan hasilnya adalah properti.

Mari kita lihat sebuah contoh. Buat berbagai model sederhana:

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

Saring array berdasarkan properti isHidden. Di bawah ini adalah 3 contoh dengan hasil yang sama:

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

Fungsionalitas yang dideklarasikan tidak berfungsi dalam contoh berikut:

//   
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)

Juga, tidak seperti keyPath, pelengkapan otomatis tidak berfungsi.

Lebih mudah digunakan untuk bekerja dengan array dalam fungsi seperti filter, peta, pengurangan, pengurutan, dan sejenisnya.

SR-6118 Langganan Dapat Berisi Pengaturan Default


Semua parameter fungsi dapat diatur ke nilai default. Buat struktur Kotak yang berisi array elemen, dan fungsi subskrip untuk mengaksesnya.

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

Sekarang, untuk mengakses elemen pertama, Anda dapat menghilangkan indeks:

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

SR-2189 Fungsi Lokal Mendukung Parameter Default dari Visibilitas Eksternal


Dalam praktik sehari-hari, fungsi lokal jarang digunakan. Mungkin sulit untuk membenarkan penggunaannya. Namun demikian, saya akui bahwa dalam kasus-kasus tertentu ini mungkin berguna.

Sebagai contoh, kita akan membuat fungsi di mana kita akan menggambarkan fungsi lokal:

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

Sebagai parameter default untuk fungsi calculWidth, kita bisa menggunakan nilai-nilai di dalam fungsi getXPosition.

SE-0253 Menggunakan Nilai sebagai Fungsi


Fungsionalitas, mirip dengan @dynamicCallable, memungkinkan Anda menggunakan nilai sebagai fungsi. Tetapi ini merupakan implementasi dari "panggilan statis".

Dalam praktiknya, semuanya sangat sederhana: untuk memanggil fungsi, Anda bisa merujuk ke nilai sebagai metode.

Buat struktur Player:

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

Buat instance Player dan rujuk sebagai fungsi:

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

Pada saat yang sama, dilarang untuk melemparkan, dan karena itu, melewatkan objek sebagai fungsi:

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

Anda bisa menambahkan metode sebanyak panggilanFungsi ke kelas, struktur, atau protokol:

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

Penerapan dimungkinkan dalam nilai-nilai yang merupakan fungsi matematika, ekspresi kompleks atau dalam kasus di mana nilai memiliki satu fungsi dominan. Namun demikian, Anda tidak boleh menyalahgunakan fungsi ini, karena dapat menyesatkan.

SR-4206 Fixed bug dengan fungsi menimpa dengan parameter generik


Sekarang, mengesampingkan fungsi, Anda tidak dapat mengubah atau menambahkan batasan pada tipe generik. Sebagai contoh, buat kelas CarBuilder dan mewarisinya dengan mengganti metode 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 Memperluas protokol tanpa batasan kelas mewarisi pembatasan ini


Dalam hal pembatasan pada Diri, ekstensi akan menerapkan pembatasan.

Misalnya, buat Menu dan protokol ekstensi dengan batasan kelas:

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

Pada saat yang sama, setter nonmutating, seolah-olah protokol memiliki batasan kelas.

SR-11429 Casting untuk fungsi dengan label


Saat casting fungsi untuk mengetik label sekarang dihapus. Berkat ini, Anda dapat menggunakan fungsi dengan label. Sebelumnya, fungsi ini hanya berfungsi dalam fungsi tanpa label:

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

Namun, nilai default tidak akan disimpan:

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

Ini juga berlaku untuk obat generik, sehingga kode ini tidak lagi valid.

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 Fungsi filter (_ :) disebut dalam urutan yang diharapkan dalam koleksi malas


Buat koleksi malas dan panggil metode penghitungan:

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

Sebelumnya, hasil panggilannya adalah sebaliknya: B A.

SR-2790 Sejumlah inisialisasi tipe keluarga UnsafePointer / UnsafeBufferPointer sekarang mengeluarkan peringatan


Pembatasan berlaku untuk parameter string, array, dan inout yang tidak ada di luar panggilan fungsi.

Buat struktur yang menggunakan UnsafePointer sebagai parameter selama inisialisasi:

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: "")
}

Ada 9 perubahan dalam versi ini, namun, mereka pasti memperkenalkan fungsionalitas baru. Saya berasumsi bahwa yang paling banyak digunakan saat ini adalah KeyPath sebagai fungsi.

Dan kami menantikan versi berikutnya. Rupanya, itu akan mendukung Swift pada Windows dan fitur menarik akan muncul, seperti penggunaan diri dalam melarikan diri penutupan tanpa mengakses melalui diri. * ( SE-0269 ) dan fungsi generik ( SE-0267 ) akan berkembang .

Sumber

All Articles