2017-12-10 2 views
1

Wie geben Sie an, dass ein generischer Typparameter nur ein Protokoll sein kann (oder ein Protokoll, das diesem Protokoll entspricht), und keine Klasse, die diesem Protokoll entspricht?Swift Generics: Constrain Typ Parameter zu Protokoll

Zum Beispiel:

import Foundation 

@objc protocol MyProtocol { 
    var name: String { get } 
} 

@objc protocol MySubProtocol: MyProtocol { 
    func foo() 
} 

class MyImplementation: MySubProtocol { 
    var name: String 

    init(name: String) { 
     self.name = name 
    } 

    func foo() { 
     print("Foo! Name: \(self.name)") 
    } 
} 

class InterfaceMaker<T: MyProtocol> { 
    init() {} 

    func makeInterface() -> NSXPCInterface { 
     return NSXPCInterface(with: T.self) // Cannot convert value of type 'T.Type' to expected argument type 'Protocol' 
    } 


    func getProxy() -> T? { 
     // Some magic in here involving `NSXPCConnection.remoteObjectProxy` 
    } 
} 

InterfaceMaker<MySubProtocol>().makeInterface() // No error, as expected 
InterfaceMaker<MyImplementation>().makeInterface() // No error, but should not work! 

Wie gebe ich, dass ein generischer Typ Parameter ein Protokoll enthalten sein sollte?

Ich möchte T nur Protokolle konform MyProtocol (wie MySubProtocol) zu beschränken. Aber das Problem ist, ich weiß nicht, wie man verhindert, dass T eine Klasse ist (wie).

Ich versuchte bereits, T.self zu beschränken (ich versuchte, where T.self : Protocol zu verwenden, aber das verursachte den Fehler 'self' is not a member type of 'T').

Wie lege ich fest, dass Tein Protokoll zu MyProtocol, aber keine Klasse konform sein muss? Wenn das unmöglich ist, kann ich mindestens angeben, dass T irgendein Protokoll sein sollte? Es ist auch in Ordnung, wenn ich entweder eine class-only protocol machen muss.

Passing MySubProtocol als nicht-generischer Parameter ist nicht, was ich suche, wie ich es auch für die InterfaceMaker.getProxy() Funktion dieses Protokoll als eine Art in der Lage sein möchten zu verwenden. Darüber hinaus ist diese Funktion einfach MyProtocol zurückgeben (mit anderen Worten, InterfaceMaker nicht generisch zu sein) ist auch keine Option.

HINWEIS: Um vollständig klar zu sein, der Grund, warum ich T brauchen ein Protokoll zu sein, ist, dass ich es NSXPCInterface.init(with:), passieren werde, die eine nimmt Protocol (die durch SomeProtocol.self wenn SomeProtocol ist, erhalten werden kann @objc) . Dies bedeutet, dass SomeProtocol.self.Type ist oder entspricht

Wenn dies nicht möglich ist, geben Sie bitte eine vollständige Erklärung warum. Erwähnen Sie auch, ob dies in einer zukünftigen Swift-Version unterstützt werden könnte.

EDIT: Eine andere Art der Formulierung ist, dass T.self is AnyObject.Type nie wahr sein sollte. Ich würde das lieber zur Kompilierzeit überprüfen als eine Laufzeitprüfung oder -überprüfung.

+0

Warum interessieren Sie sich T beschränken sich nur auf Protokolle? Warum kann ich keine Oberklasse benutzen? – Alexander

+0

@Alexander Was meinst du? Warum kannst du nicht eine Oberklasse für was verwenden? – Coder256

+0

Was ist, wenn ich eine Klassenvererbungshierarchie verwende (zB 'Car',' SportsCar: Car', 'FamilyCar: Car') und keine Protokollhierarchie (zB' CarProtocol', 'SportsCarProtocol: CarProtocol',' FamilyCar: Protokoll "). Warum solltest du mich davon abhalten, 'Car' als Schnittstelle zu benutzen, und mich stattdessen zwingen,' CarProtocol' zu verwenden? – Alexander

Antwort

1

Sie können überprüfen, ob T dem Protokoll AnyObject entspricht, das implizit allen Klassen entspricht, jedoch keine Protokolle.

Also, in InterfaceMaker:

class InterfaceMaker<T: MyProtocol> { 
    init() {} 

    func makeInterface() -> NSXPCInterface { 
     if T.self is AnyObject.Type { 
      // T is a class 
     } else { 
      return NSXPCInterface(with: T) 
     } 
    } 


    func getProxy() -> T? { 
     // Some magic in here involving `NSXPCConnection.remoteObjectProxy` 
    } 
} 
+0

Korrigieren Sie mich, wenn ich falsch verstanden habe, aber ich versuche nicht, die Protokolle selbst generisch zu machen, sondern nur ein Protokoll als Typparameter zu verwenden (und diesen Typparameter nur auf Protokolle zu beschränken). – Coder256

+0

Oh Entschuldigung, ich habe missverstanden was du meintest. Ich werde die Antwort umschreiben. – barbarity

+0

Ich habe die Antwort geändert. Ich hoffe, es ist das, was Sie versuchen zu tun – barbarity

Verwandte Themen