web-dev-qa-db-fra.com

Swift-Generics: "Impossible de spécialiser le type non générique"

J'essaie d'implémenter du code orienté objet en utilisant un protocole générique. Disons que j'ai deux protocoles

protocol Executable: class {
    func execute()
}

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

J'ai mis en place un décorateur pour l'exécutable:

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
    }
}

Maintenant, je ne veux pas l'utiliser dans un cours comme celui-ci:

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

Mais ce n'est pas possible car le protocole lui-même n'est pas générique, seulement la fonction. Le compilateur me dit:

Impossible de spécialiser le type non générique 'Dockable'

L'idée est de l'utiliser comme ça:

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

Comment la syntaxe correcte dans Swift 3 rend-elle le compilateur heureux?

MISE À JOUR 1

J'ai fait des progrès avec le code suivant:

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

Cela semble étrange, peut-être que quelqu'un a une meilleure idée? En utilisant la classe maintenant, je reçois:

Le paramètre générique 'DOCKABLE' n'a pas pu être déduit

Donc, mes questions n'ont pas changé:

Comment la syntaxe correcte dans Swift 3 rend-elle le compilateur heureux?

Mise à jour 2

Il semble qu'il ne soit pas possible d'utiliser les protocoles génériques Swift (ou mieux: associés au type) dans la programmation orientée objet basée sur un protocole. 

Nous devons donc les emballer dans une sorte de conteneur et perdre l’approche basée sur les protocoles ou nous devons définir des protocoles différents pour chaque situation. 

Parce que travailler sans protocole n'est pas une option pour moi, je dois écrire différents protocoles sans génériques. Honte à Swift ???? 

8
ObjectAlchemist

Je ne suis pas sûr que votre problème puisse être résolu sans effacement de types, car vous ne pouvez pas utiliser de protocoles avec des types associés pour des types de variables ou des paramètres de fonctions.

Essayez la solution avec effacement de type:

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()
    }
}

Votre compilateur sera content, je l'ai vérifié:

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)
3
ixrevo

Si je ne me trompe pas, vous recherchez Composition du protocole (conformité multiprotocole), non? Vous pouvez ensuite utiliser différents de vos décorateurs après.

Peut-être cherchez-vous ceci: Swift 3 protocol<A, B> et dans 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/

Plusieurs types de contraintes dans Swift

1
smat88dd