在包含的泛型类型参数上键入约束

时间:2018-03-25 01:39:20

标签: swift generics

我希望以下代码在两种情况下都能打印“扩展名”。但扩展的类型约束不会对包含的泛型类型生效。在约束协议时我也看到相同的行为。

class Generic1<T1> {
    func doSomething() {
        print("base")
    }
}

extension Generic1 where T1 == String {
    func doSomething() {
        print("extension")
    }
}

class Generic2<T2> {
    private let generic1 = Generic1<T2>()
    func doSomething() {
        generic1.doSomething()
    }
}

Generic1<String>().doSomething()    // prints extension
Generic2<String>().doSomething()    // prints base

我目前唯一的解决方法是限制外部泛型,如下所示:

extension Generic2 where T2 == String {
    func doSomething() {
        generic1.doSomething()
    }
}

为什么会这样?有更好的解决方案吗?

修改:为了完整起见,适合我案例的解决方法如下:

class Generic1<T1> {
    func doSomething() {
        print("base")
    }
}

class StringGeneric1: Generic1<String> {
    override func doSomething() {
        print("extension")
    }
}

class Generic2<T2> {
    private let generic1: Generic1<T2>

    init (_ generic1: Generic1<T2>) {
        self.generic1 = generic1
    }

    func doSomething() {
        generic1.doSomething()
    }
}

Generic1<String>().doSomething()    // prints "base"
Generic2<String>(StringGeneric1()).doSomething()    // prints "extension"

2 个答案:

答案 0 :(得分:1)

问题是扩展中定义的方法是静态分派的。所以当你有:

class Generic2<T2> {
    private let generic1 = Generic1<T2>()
    func doSomething() {
        generic1.doSomething()
    }
}

编译器无法在此知道T2是否将成为String,因此它会生成对基类中方法的调用。当您明确指定T2String时,使用该信息,编译器可以在此处生成对扩展方法的调用。但是,否则,T2的类型在运行时才会知道,因此您无法通过静态分派来访问扩展方法。

答案 1 :(得分:0)

使用Swift 4.2添加conditional conformances时可以解决这个问题