Swift 泛型函数受 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 类型。因此,错误是不正确的。 ...正确的?这段代码 and/or 编译器怎么了?
编辑:这里是一个例子,给出了五个类似的通用函数。它们都是根据我想要的功能来衡量的,任何大写的评论都会指出它们未能满足我的需求的方式。为了使示例更具体一些,我将 AnyObject
替换为具体的 class C0
。请注意 C2
subclasses C1
subclasses 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
.
相同的编译时行为
Therefore, the error is incorrect. ...Right?
嗯...当前的约束系统还不够强大,无法允许这种约束。好消息是广义超类型约束在 Swift 路线图上,如 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 可以使用此功能才能使其正常工作。
考虑以下代码:
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 类型。因此,错误是不正确的。 ...正确的?这段代码 and/or 编译器怎么了?
编辑:这里是一个例子,给出了五个类似的通用函数。它们都是根据我想要的功能来衡量的,任何大写的评论都会指出它们未能满足我的需求的方式。为了使示例更具体一些,我将 AnyObject
替换为具体的 class C0
。请注意 C2
subclasses C1
subclasses 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
.
Therefore, the error is incorrect. ...Right?
嗯...当前的约束系统还不够强大,无法允许这种约束。好消息是广义超类型约束在 Swift 路线图上,如 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 可以使用此功能才能使其正常工作。