【问题标题】:How to make a computed property of a generic class depend on the class constraints如何使泛型类的计算属性取决于类约束
【发布时间】:2017-05-19 14:50:41
【问题描述】:

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

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&lt;B1&gt;().v 返回 0,但 C&lt;B2&gt;().v 抱怨 v 的使用不明确。如果我把v 变成一个可行的方法

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

现在C&lt;B1&gt;().v() 返回 0,C&lt;B2&gt;().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&lt;B1&gt;().vE&lt;B2&gt;().v 都返回0,即只使用get 的无约束实现。我可以“强制”编译器选择正确的实现吗?

有什么想法吗?对我来说,这听起来像是 Swift 的一个不足/错误,但我还不够确定。我在 XCode 8.2.1 中使用 Swift 3

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

【问题讨论】:

    标签: swift generics


    【解决方案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  }
    

    【讨论】:

    • 这回答了我提出的问题,涵盖了很多案例。除了(这是我真正需要的:-)),当AExpressibleByNilLiteral 并且我的实现需要生成T 类型的nil,如果TExpressibleByNilLiteral。我会接受你的回答,因为它回答了我提出的问题,但你愿意对此发表评论吗?
    • 不确定我是否理解。为了清楚起见,您能否举个例子,也许是在另一个问题中?
    猜你喜欢
    • 2021-01-30
    • 1970-01-01
    • 1970-01-01
    • 2017-01-21
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2019-10-15
    • 1970-01-01
    相关资源
    最近更新 更多