gpt4 book ai didi

ios - 如何用 where 子句重构这个 Swift 协议(protocol)?

转载 作者:行者123 更新时间:2023-12-04 03:37:38 27 4
gpt4 key购买 nike

我有一个 Savable具有多个版本 save() 的协议(protocol)基于C1的一致性的方法和 C2 .然后还有一个Downloadable符合 Savable 的协议(protocol)调用 Savable 的协议(protocol)的save()基于C1的一致性的方法和 C2 .
从下面的示例代码可以看出,download()方法都是一样的。有没有办法通过删除重复的功能来简化这段代码?还是我应该使用另一种完全不同的方法来获得相同的结果?
PS:两个SavableDownloadable由于某些未提及的技术原因,需要成为协议(protocol)。此外,C1C2两者都有 Self 或关联的类型要求,因此无法执行类型检查。

// Constraint
protocol C1 { }
protocol C2 { }

// Savable
protocol Savable { }
extension Savable {
func save() {
print("Perform basic save")
}
}

extension Savable where Self: C1 {
func save() {
print("Perform save C1")
}
}

extension Savable where Self: C1 & C2 {
func save() {
print("Perform save C1 & C2")
}
}

// Downloadable
protocol Downloadable: Savable { }
extension Downloadable {
func download() {
print("Perform download")
save()
}
}

extension Downloadable where Self: C1 {
func download() {
print("Perform download")
save()
}
}

extension Downloadable where Self: C1 & C2 {
func download() {
print("Perform download")
save()
}
}

// Usage
class MyClassC1: Downloadable, C1 { }
let obj1 = MyClassC1()
obj1.download()
// Output:
// Perform download
// Perform save C1

class MyClassC1C2: Downloadable, C1, C2 { }
let obj2 = MyClassC1C2()
obj2.download()
// Output:
// Perform download
// Perform save C1 & C2
提前致谢!

最佳答案

这种方法非常脆弱。您依靠编译时检查来执行重载,并且只有在编译时知道类型时才有效。只有在 save() 的版本之间没有功能差异时才应该做这种事情。 (例如,如果唯一的区别是性能)。协议(protocol)不是子类。
作为问题的一个例子,考虑:

func getit(what: Downloadable) {
what.download()
}

getit(what: obj2) // => "Perform basic save", not "perform save C1 & C2"
即使您添加泛型,它也会以完全相同的方式“失败”:
func getit<D: Downloadable>(what: D) { ... }
这并不是真正的失败。所有编译器在编译时都知道这是可下载的类型,因此它将调用可下载的实现。
如果你想要运行时调度,你需要在运行时使用 as? 进行调度。 .摆脱所有 where扩展和替换 save和:
protocol Savable { }
extension Savable {
func save() {
if self is C1 & C2 {
print("Perform save C1 & C2")
} else if self is C1 {
print("Perform save C1")
} else {
print("Perform basic save")
}
}
}
注意顺序很重要(在测试 C1 & C2 之前测试 C1 )。决定如何调度取决于您。
不幸的是,这要求您在编译时静态地了解所有类型并将它们放在一个地方。可以解决这个问题并集中注册“保护程序”,但这有点棘手,除非你真的需要它,否则我不特别推荐这个。然而,这就是你将如何做到的。
// A Saver object that knows all the "rules". It maps conformances to functions
class Saver {
static let shared = Saver()

private var savers: [(predicate: (Any) -> Bool, save: (Any) -> ())] = []

func addSaver<T>(of: T.Type, save: @escaping (T) -> ()) {
savers.append((predicate: { $0 is T }, save: { save($0 as! T) }))
}

func save(value: Any) {
for (predicate, save) in savers {
if predicate(value) {
save(value)
return
}
}
fatalError("Couldn't save") // Or some default behavior or whatever
}
}

// Now you configure the Saver. Order is important!
let saver = Saver.shared
saver.addSaver(of: (C1 & C2).self, save: { _ in print("Perform save C1 & C2") })
saver.addSaver(of: C1.self, save: { _ in print("Perform save C1") })
saver.addSaver(of: Savable.self, save: { _ in print("Perform basic save") })

// Savable
protocol Savable { }
extension Savable {
func save() {
// And use it here
Saver.shared.save(value: self)
}
}
使用它,您可能会发现许多小角落案例。就像如果有人想在程序中的某个随机点(可能在另一个模块中?)添加另一个保护程序会发生什么,所以您可能需要重新排序测试,或者如果两个保护程序同样“特定”所以你不知道哪个一个更喜欢。这些正是编译器在处理此类问题时面临的极端情况。

关于ios - 如何用 where 子句重构这个 Swift 协议(protocol)?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/66585126/

27 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com