如何创建泛型类的计算属性取决于类约束

时间:2017-01-05 06:34:56

标签: swift generics

我有一个协议和两个类,其中一个采用它

protocol A { }
class B1 { }
class B2: A { }

我想要一个泛型类的计算属性,这取决于类型是否采用A。我试过这个

class C<T> {
    var v: Int { get { return 0 } }
}
extension C where T: A {
    var v: Int { get { return 1 } }
}

现在C<B1>().v返回0,但C<B2>().v抱怨对v的模糊使用。如果我将v转换为可行的方法

class D<T> {
    func v() -> Int { return 0 }
}
extension D where T: A {
    func v() -> Int { return 1 }
}

现在C<B1>().v()返回0,C<B2>().v()按预期返回1.

为什么getter方法与方法方法不同?我可以使计算属性工作吗?我试过了

class E<T> {
    var v: Int { get { return get() } }
    func get() -> Int { return 0 }
}
extension E where T: A {
    func get() -> Int { return 1 }
}

但现在E<B1>().vE<B2>().v都返回0,即仅使用get的无约束实现。我可以“强制”编译器选择正确的实现吗?

有什么想法?对我来说,这听起来像Swift的缺陷/错误,但我不知道足够肯定。我在XCode 8.2.1中使用Swift 3

更新:我刚刚注意到,即使我的方法解决方案并不总是有效,编译器有时会决定采用更一般的实现方式。我不确定是什么决定这个(我的实际项目更大,提取一个简单的例子有点困难)...所以我可能会遇到一个更普遍的问题:如何可靠地创建泛型类的属性/方法针对其类型参数的不同约束做不同的事情?

1 个答案:

答案 0 :(得分:1)

如果您主动检查计算属性中T的类型,它可能会有效:

class D<T> {
    var v: Int {
        get {
            if let _ = T.self as? A.Type {
                return 1
            } else {
                return 0
            }
        }
    }
}

let c = D<B2>()
print (c.v) // the output is 1

甚至更短:

var v: Int { return T.self is A.Type ? 1 : 0  }