如何使用关联类型和数组扩展协议

How to make extension to protocol using associatedtype and array

假设我有这些协议

protocol Actionable {

}

protocol M: class {
    associatedtype Action: Actionable
    var views: [Action] { get set }
}

和两个函数

func f(view: Actionable) {

}

func g(views: [Actionable]) {

}

然后我扩展协议 M

extension M {
    func add(view: Action) {
        views.append(view)
        f(view)
        g(views)
    }
}

当我调用 f(view 时它起作用了。但是当我调用 g(views) 它显示错误

Cannot convert value of type '[Self.Action]' to expected argument type '[Actionable]'

这里 g 接受数组而不是像 f 这样的单个对象。为什么数组在这种情况下很重要?如何解决这个问题?

附带说明一下,这似乎也是通用结构的错误

protocol Actionable {

}

struct M<T: Actionable> {
  var views: [T]
}

func g(views: [Actionable]) {

}

extension M {
  func add() {
    g(views)
  }
}

这是对以下事实的扩展:Swift 中的数组对其可以隐式转换为的类型有限制——这是我讨论的 Swift 中泛型不变性的结果进一步 .

一个可能的解决方案是使用 map 以便将每个元素单独从 Action 转换为 Actionable(元素可以自由向上转换,但数组本身不能):

extension M {
    func add(view: Action) {
        views.append(view)
        f(view)
        g(views.map{[=10=]})
    }
}

然而,在您的具体情况下,我只是建议使您的 fg 函数通用,以维护您提供给它们的具体类型(除非您特别希望它们是类型擦除):

func f<T:Actionable>(view: T) {
    ...
}

func g<T:Actionable>(views: [T]) {
    ...
}

extension M {
    func add(view: Action) {
        views.append(view)
        f(view)
        g(views)
    }
}

现在,当您调用它们时,Action 的泛型类型将得到维护,如果您想传递参数,则可以提供更好的类型安全性。