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

时间:2016-05-29 19:26:17

标签: arrays swift protocols extension-methods associated-types

说我有这些协议

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)时,它会显示错误

  

无法将'[Self.Action]'类型的值转换为预期参数类型'[可操作]'

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

作为旁注,这似乎也是泛型结构的错误

protocol Actionable {

}

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

func g(views: [Actionable]) {

}

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

1 个答案:

答案 0 :(得分:1)

这是Swift中的数组对它们可以隐式转换为的类型有限制这一事实的扩展 - 这是Swift中泛型不变性的结果,我将进一步讨论in this post

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

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

但是,在您的具体情况下,我建议您将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的泛型类型,如果你想传递参数,可以提供更好的类型安全性。