简体   繁体   English

为什么泛型不通过约束进一步在调用链中参与方法重载?

[英]Why does the generic type not participate in method overloading via constraint further down the call chain?

Swift allows generic methods to be overloaded by the constraints placed upon the generic types passed in. If you use this with concrete types, then the type passed in will participate in this overloading and constraints will be inferred from that type. Swift允许通过传入的泛型类型上的约束来重载泛型方法。如果将其与具体类型一起使用,则传入的类型将参与此重载,并且将从该类型推断出约束。

As soon as a generic method delegates to another with overload resolution, the constraints can no longer be inferred and will instead utilize the constraints already placed on the type from above. 一旦泛型方法委托给另一个具有重载解决方案的方法,就不再可以推断出约束,而将利用上面已经放置在类型上的约束。

protocol Conformance {}

extension String : Conformance {}

// #1
func baseMethod<T>(_ value: T) {
    let isConforming = T.self is Conformance.Type
}

// #2
func baseMethod<T>(_ value: T) where T : Conformance {
    let isConforming = T.self is Conformance.Type
}

func delegatingMethod<T>(_ value: T) {
    baseMethod(value)
}

func run() {
    // Calls #2, isConforming = true
    baseMethod(String())
    // Calls #1, isConforming = true
    delegatingMethod(String())
}

I assume this is there so that you have sufficient type information from the call site about what constraints are applicable no matter where the generic type is used, but it seems to severely and artificially limit the utility of overloading by constraint. 我认为这里是这样,以便无论使用通用类型在哪里,您都可以从调用站点获得有关适用哪些约束的足够类型信息,但这似乎通过约束严格地人为地限制了重载的效用。

Are there any known workarounds to this oddity? 有没有已知的解决方法来解决这一问题? Something that emulates this would be extremely useful. 模仿这一点将非常有用。

Swift allows generic methods to be overloaded by the constraints placed upon the generic types passed in. Swift允许通过传入的泛型类型上的约束来重载泛型方法。

Yes...but be very clear that this is a static overload , not a dynamic override . 是的...但是要非常清楚,这是静态重载 ,而不是动态替代 It is based on types that can be proven at compile-time. 它基于可在编译时证明的类型。

func delegatingMethod<T>(_ value: T) {
    baseMethod(value)
}

We're compiling this now, and we need to write it as a concrete, static function call, possibly inlined, into the binary. 我们现在正在编译它,我们需要将它作为一个具体的静态函数调用(可能内联)写入二进制文件中。 What do we know about T ? 我们对T了解多少? We know nothing about T , so any where clause will fail. 我们对T 一无所知 ,因此任何where子句都会失败。

We don't even know about how this function is called, because the call may come from another compile unit or module. 我们甚至不知道如何调用此函数,因为该调用可能来自另一个编译单元或模块。 While in principle, it could have different semantics based on access level, such that one version were used when it is private and all calls can be evaluated, and another used when it's public, that would be a really horrible source of bugs. 原则上,它可以基于访问级别具有不同的语义,例如,一个版本在私有时可以使用,并且可以评估所有调用,而另一个版本在公开时可以使用,这将是一个非常可怕的错误源。

What you're asking for is that delegatingMethod defer its decision about what function call to make until runtime. 您要问的是delegatingMethod将决定执行什么函数的决定推迟到运行时。 That's not how generics work. 这不是泛型的工作方式。 Moreover, you're asking that all the where clauses be encoded somewhere in the binary so that they can be evaluated at runtime. 此外,您要求将所有where子句编码为二进制文件中的某个位置,以便可以在运行时对其进行求值。 Also not how generics work. 同样不是泛型的工作方式。 That would require a much more dynamic dispatch system than Swift wants to implement. 这将需要比Swift想要实现的动态系统更多的调度系统。 It's not impossible; 这不是不可能的。 it's just a completely different animal, and prevents lots of optimizations. 它只是一种完全不同的动物,并且阻止了许多优化。

This feels like you're trying to reinvent class inheritance with protocols and generics. 感觉就像您正在尝试使用协议和泛型来重塑类继承。 You can't. 你不能 They're different solutions and have different features. 它们是不同的解决方案,并且具有不同的功能。 Class inheritance is fundamentally dynamic. 类继承从根本上说是动态的。 Protocols and generics are fundamentally static. 协议和泛型基本上是静态的。 If you want dynamic dispatch based on specific types, use classes. 如果要基于特定类型进行动态调度,请使用类。

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

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