Swift-Generics:“不能专门化非泛型类型”

时间:2017-03-19 13:15:21

标签: swift oop generics

我尝试使用通用协议实现面向对象的代码。 假设我有两个协议

protocol Executable: class {
    func execute()
}

protocol Dockable: class {
    associatedtype T
    func dock(object: T)
}

我为Executable实现了一个装饰器:

final class DockableExecutable: Executable, Dockable {
    typealias T = Executable
    private let decorated: Executable
    private var docked: Executable?
    init(_ decorated: Executable) {
        self.decorated = decorated
    }
    // from Executable
    func execute() {
        decorated.execute()
        docked?.execute()
    }
    // from Dockable
    func dock(object: Executable) {
        docked = object
    }
}

现在我不想在类似的课程中使用它:

final class MyViewController: UIViewController {
    init(save: Executable, uiUpdateConnector: Dockable<Executable>) {}
}

但这是不可能的,因为协议本身不是通用的,只是函数。编译器告诉我:

  

无法专门化非泛型类型“可停靠”

这个想法就是这样使用它:

let dockableExecutable = DockableExecutable(
    SQLUpdateExecutable(/** dependencies **/)
)
let controller = MyViewController(save: dockableExecutable, uiUpdateConnector: dockableExecutable)

Swift 3中的正确语法如何使编译器满意?

更新1

我使用以下代码取得了一些进展:

final class MyViewController: UIViewController {
    init<DOCKABLE: Dockable>(save: Executable, uiUpdateConnector: DOCKABLE) where DOCKABLE.T: Executable {}
}

看起来很奇怪,也许有人有更好的主意?现在使用课程时我得到:

  

无法推断通用参数'DOCKABLE'

所以我的问题没有改变:

Swift 3中的正确语法如何使编译器满意?

更新2

似乎不可能在基于协议的面向对象编程中使用swift通用(或更好:类型相关)协议。

因此我们必须将它们包装到某种容器中并且松散基于协议的方法,或者我们必须为每种情况定义不同的协议。

因为没有协议的工作对我来说是没有选择的,所以我必须编写不带泛型的不同协议。羞愧快速

2 个答案:

答案 0 :(得分:3)

我不确定您的问题是否可以在没有类型擦除的情况下解决,因为您无法将相关类型的协议用于变量类型或函数参数。

尝试使用类型擦除的解决方案:

final class AnyDockable<U>: Dockable {
    typealias T = U

    let _dock: (U) -> Void
    let _execute: () -> Void

    init<Base: Dockable & Executable>(base: Base) where Base.T == U {
        _dock = base.dock
        _execute = base.execute
    }

    func dock(object: U) {
        _dock(object)
    }

    func execute() {
        _execute()
    }
}

您的编译器会很高兴,我已经检查过了:

class Exe: Executable {
    func execute() {
        print("")
    }
}
let executable: Executable = Exe()

let de = AnyDockable(base: DockableExecutable(executable))

final class MyViewController: UIViewController {

    init(save: Executable, uiUpdateConnector: AnyDockable<Executable>) {
        super.init(nibName: "", bundle: nil)
    }

    required init?(coder aDecoder: NSCoder) {
        fatalError("init(coder:) has not been implemented")
    }
}

MyViewController(save: executable, uiUpdateConnector: de)

答案 1 :(得分:1)

如果我没有弄错你正在寻找协议组合(多协议一致性),不是吗?然后,您可以使用不同的装饰器。

也许您正在寻找: Swift 3 protocol<A, B>,以及 Swift 4 A & B

final class MyViewController: UIViewController {
    init(save: Executable, uiUpdateConnector: protocol<Dockable, Executable>) {}
}

https://developer.apple.com/library/content/documentation/Swift/Conceptual/Swift_Programming_Language/Protocols.html

http://braking.github.io/require-conformance-to-multiple-protocols/

Multiple Type Constraints in Swift