繁体   English   中英

Swift 通用 function 受 class 通用约束

[英]Swift generic function constrained by class generic

考虑以下代码:

public class Test<P: AnyObject> {
    public func foo<T: P>(_ t: T.Type) -> T { // ERROR: Type 'T' constrained to non-protocol, non-class type 'P'
        // stuff happens
    }
}

注意第二行的错误,声称P不是 class 类型。 但是,在第 1 行, P被声明为扩展AnyObject ,因此必须是 class 类型。 因此,错误是不正确的。 ...正确的? 这段代码和/或编译器是怎么回事?


编辑:这是一个给出五个类似通用函数的示例。 它们都是根据我想要的功能来衡量的,大写的任何评论都指出了它们未能满足我的愿望的方式。 为了使示例更加具体,我将AnyObject替换为具体的 class C0 请注意, C2子类C1子类C0 ,并且CX是不相关的。

public class C0 {
    public required init() {
    }
}

public class C1: C0 {
    public required init() {
    }
}

public class C2: C1 {
    public required init() {
    }
}

public class CX {
    public required init() {
    }
}

//public class D0<P: AnyObject> { // AnyObject replaced with C0 for a more concrete example
public class D0<P: C0> {
    public func foo0<T: P>(_ t: T.Type) -> T { // DOESN'T COMPILE
        return t.init()
    }
    public static func test_foo0() {
//      let c2_0: C2 = D0<C1>().foo0(C2.self) // Function sig doesn't compile; can't test
//      let cX_0: CX = D0<C1>().foo0(CX.self) // Function sig doesn't compile; can't test
    }



    // Shadows P in favor of its own local generic parameter P (T would accomplish the same result)
    public func foo1<P>(_ t: P.Type) -> P { // TOO PERMISSIVE
        return t.init() // Should compile ; does NOT compile
    }
    public static func test_foo1() {
        let c2_1: C2 = D0<C1>().foo1(C2.self) // Should compile ; does compile
        let cX_1: CX = D0<C1>().foo1(CX.self) // Should not compile ; DOES compile
    }



    public func foo2(_ t: P.Type) -> P { // TOO RESTRICTIVE
        return t.init()
    }
    public static func test_foo2() {
        let c2_2: C2 = D0<C1>().foo2(C2.self) // Should compile ; does NOT compile
        let cX_2: CX = D0<C1>().foo2(CX.self) // Should not compile ; does not compile
    }



    // Hardcoded to match the constraint that is *on P*
    public func foo3<T: C0>(_ t: T.Type) -> T { // TOO PERMISSIVE
        return t.init()
    }
    public static func test_foo3() {
        let c0_3: C0 = D0<C1>().foo3(C0.self) // Should not compile ; DOES compile
    }



    // Hardcoded to match the actual generic parameter of my example
    public func foo4<T: C1>(_ t: T.Type) -> T { // HARDCODED TO MATCH MY SINGLE EXAMPLE
        return t.init()
    }
    public static func test_foo4() {
        let c2_4: C2 = D0<C1>().foo4(C2.self) // Should compile ; does compile
        let c0_4: C0 = D0<C1>().foo4(C0.self) // Should not compile ; does not compile
        let cX_4: CX = D0<C1>().foo4(CX.self) // Should not compile ; does not compile
    }
}

第一个示例foo0是我期望的,但它无法编译。 在第五个示例foo4中,我将通用参数P硬编码为C1 ,它应该在D0<C1>中解析的方式,我在每个测试中使用的方式。 这按预期工作,但不再是通用的。

我断言foo0应该编译,并且(在D0<C1>下)具有与foo4相同的编译时行为。

因此,错误是不正确的。 ...正确的?

嗯……当前的约束系统还不够强大,无法允许这种约束。 好消息是广义超类型约束在 Swift 道路 map 上,如Generics Manifesto中所述。

出于相同的原因,以下内容也不会编译:

func test<A, B>(_ a: A, _ b: B) where A: AnyObject, B: A {
    // ^^^  Type 'B' constrained to non-protocol, non-class type 'A'
}

宣言中的例子都不是:

protocol P {
  associatedtype Base
  associatedtype Derived: Base
}

不幸的是,您必须等到 Swift 可以使用此功能,才能使其按您的意愿工作。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM