Я портирую библиотеку Java на Swift 2.0 и испытываю некоторые проблемы с дженериками.Есть ли способ определить соответствие субпротокола, например, в соответствии с общим протоколом в Swift 2 (во время выполнения или во время компиляции)?
У меня есть следующая иерархия протоколов:
public protocol Graph {
typealias V: Hashable
typealias E: Hashable
func getAllEdges(sourceVertex: V, targetVertex: V) -> Set<E>?
func getEdge(sourceVertex: V, targetVertex: V) -> E?
func getEdgeFactory() -> EdgeFactory<V, E>?
func addEdge(sourceVertex: V, targetVertex: V) -> E?
func addEdge(sourceVertex: V, targetVertex: V, e: E) -> Bool
func addVertex(v: V) -> Bool
func containsEdge(sourceVertex: V, targetVertex: V) -> Bool
func containsEdge(e: E) -> Bool
func containsVertex(v: V) -> Bool
func edgeSet() -> Set<E>
func edgesOf(v: V) -> Set<E>
func removeAllEdges<T: CollectionType where T.Generator.Element == E>(edges: T) -> Bool
func removeAllEdges(sourceVertex: V, targetVertex: V) -> Set<E>?
func removeAllVertices<T: CollectionType where T.Generator.Element == V>(vertices: T) -> Bool
func removeEdge(sourceVertex: V, targetVertex: V)
func removeEdge(e: E) -> Bool
func removeVertex(v: V) -> Bool
func vertexSet() -> Set<V>
func getEdgeSource(e: E) -> V
func getEdgeTarget(e: E) -> V
func getEdgeWeight(e: E) -> Double
}
public protocol DirectedGraph: Graph {
func inDegreeOf(vertex: V) -> Int
func incomingEdgesOf(vertex: V) -> Set<E>
func outDegreeOf(vertex: V) -> Int
func outgoingEdgesOf(vertex: V) -> Set<E>
}
public protocol UndirectedGraph: Graph {
func degreeOf(vertex: V) -> Int
}
А вот определение класса, который вызывает тревогу:
public class CrossComponentIterator
<V: Hashable, E: Hashable, D, G: Graph
where G.V == V, G.E == E>
: AbstractGraphIterator<V, E>
А именно, метод, который должен INIT один из переменных, исходя из фактического типа Граф передан - DirectedGraph или UndirectedGraph.
Я попытался решить это, объявив несколько версий функции, которая делает это:
func createGraphSpecifics<DG: Graph where DG: DirectedGraph, DG.V == V, DG.E == E>(graph: DG)
-> CrossComponentIteratorSpecifics<V, E>
{
return DirectedSpecifics<V, E, DG>(graph: graph)
}
func createGraphSpecifics<UG: Graph where UG: UndirectedGraph, UG.V == V, UG.E == E>(graph: UG)
-> CrossComponentIteratorSpecifics<V, E>
{
return UndirectedSpecifics<V, E, UG>(graph: graph)
}
func createGraphSpecifics<GG: Graph where GG.V == V, GG.E == E>(graph: GG)
-> CrossComponentIteratorSpecifics<V, E>
{
fatalError("Unknown graph type instance")
}
Но, к сожалению, только последняя версия функции вызывается для любого экземпляра графа (даже если оно соответствует " DirectedGraph»или„UndirectedGraph“)
и я знаю, что, наверное, я могу решить эту проблему путем преобразования протоколов DirectedGraph и UndirectedGraph абстрактных классов (я имею в виду занятия с FatalError() в каждой объявленной функции, так как Swift Безразлично» t поддержка абстрактных классов de jure).
Но может быть, есть еще одно, более элегантное и быстрое решение?
В Java это тривиально - соответствие интерфейс проверяется во время выполнения:
if (g instanceof DirectedGraph<?, ?>) {
return new DirectedSpecifics<V, E>((DirectedGraph<V, E>) g);
} else {
return new UndirectedSpecifics<V, E>(g);
}
Редактировать вот минимальный код для того, что я пытаюсь достичь:
protocol P {
// This typealias makes impossible to use 'P'
// (or its descendants) as a type.
// It can be used only as generic constraint.
typealias A
// myfunc is needed for compiler to infer 'A'
func myfunc(a: A)
}
protocol P1:P {
func p1specific(a: A)
}
protocol P2:P {
func p2specific(a: A)
}
struct S<T:P> {
init(t: T) {
// TODO: check if 't' conforms to 'P1', 'P2', both or neither
}
}
// Examples of concrete implementations of 'P1' and 'P2'
struct S1<X>:P1{
func myfunc(a: X) {}
func p1specific(a: X) {}
}
struct S2<X>:P2{
func myfunc(a: X) {}
func p2specific(a: X) {}
}
Вы нашли решение? да, пожалуйста, поделитесь им. спасибо – user3441734