我正在将Java库移植到Swift 2.0,并且在泛型方面遇到了一些问题。
我有以下协议层次结构:
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>
也就是说,它有一个方法,应该根据传递的图的实际类型初始化它的一个变量——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转换为抽象类来解决这个问题(我指的是在每个声明的函数中都有致命错误()的类,因为Swift在法律上不支持抽象类)。
但也许还有另一种更优雅、更快捷的解决方案?
在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) {}
}
例如,有没有任何方法可以确定子协议的一致性符合Swift 2中的通用协议(在运行时或汇编)?
是
以下是我实现类型擦除的技巧,从而允许使用运行时。观察_P
:
protocol _P {
static var _A: Any.Type { get }
func _myfunc(_a: Any) -> Void?
}
extension _P where Self: P {
static var _A: Any.Type {
return A.self
}
func _myfunc(_a: Any) -> Void? {
return (_a as? A).map(myfunc)
}
}
protocol P {
typealias A
func myfunc(a: A)
}
protocol _P1:_P {
func _p1specific(_a: Any) -> Void?
}
extension _P1 where Self: P1 {
func _p1specific(_a: Any) -> Void? {
return (_a as? A).map(p1specific)
}
}
protocol P1:_P1, P {
func p1specific(a: A)
}
protocol _P2:_P {
func _p2specific(_a: Any) -> Void?
}
extension _P2 where Self: P2 {
func _p2specific(_a: Any) -> Void? {
return (_a as? A).map(p2specific)
}
}
protocol P2:_P2, P {
func p2specific(a: A)
}
现在,您可以确定一个值是符合P1
还是P2
,并相应地强制转换。此外,通用参数A
现在可通过不透明的Any.Type
获得。
(x as? _P1) != nil ? true : false
import XCPlayground
import Foundation
protocol P {}
protocol P1:P {}
protocol P2:P {}
struct S1:P1{}
struct S2:P2{}
struct S<T:P> {
var p1: P1?
var p2: P2?
init(t: T) {
p1 = t as? P1
p2 = t as? P2
}
}
let p1 = S1()
let p2 = S2()
let s1 = S(t: p1)
let s2 = S(t: p2)
dump(s1)
dump(s2)
/*
▿ S<S1>
▿ p1: S1
- Some: S1
- p2: nil
▿ S<S2>
- p1: nil
▿ p2: S2
- Some: S2
*/
使用
g is Type // trur or false
和
let v2 = v1 as? Type // v2 = v2 or nil
用swift更新
protocol P {
typealias A
}
protocol P1:P {}
protocol P2:P {}
struct S1:P1{
typealias A = Int
}
struct S2:P2{
typealias A = Double
}
struct S<T:P> {
var p1: S1?
var p2: S2?
init(t: T) {
p1 = t as? S1
p2 = t as? S2
}
}
let p1 = S1()
let p2 = S2()
let s1 = S(t: p1)
let s2 = S(t: p2)
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 {}
protocol P2:P {}
// aka 'abstract' conforming to P1
struct S1:P1{
typealias A = AnyObject
func myfunc(a: A) {}
}
// aka 'abstract' conforming to P2
struct S2:P2{
typealias A = Int
func myfunc(a: A) {}
}
// generic struct with type conforming to P
struct S<T:P> {
init(t: T) {
// TODO: check if 't' conforms to 'P1', 'P2', both or neither
if t is S1 {
print("t conforms to P1, because it is type S1")
}
if t is S2 {
print("t conforms to P2, besause it is type S2")
}
}
}
let s1 = S(t: S1()) // t conforms to P1, because it is type S1
let s2 = S(t: S2()) // t conforms to P2, besause it is type S2
// WARNING !!!!!!
// var s = s1
// s = s2 // error: cannot assign value of type 'S<S2>' to type 'S<S1>'