[英]How to call a generic function with parameter of associated type in Swift 3
Here's my sample code: 这是我的示例代码:
protocol P {
}
protocol B {
associatedtype ID: P
}
class MyClass: B {
enum ID: P {
case one
case two
}
}
func process<T: B>(_ value: T.ID) {
// do something
}
process(MyClass.ID.one) // Compile Error: cannot convert value of type 'MyClass.ID' to expected argument type '_.ID'
As you can see, I define a generic function with a parameter whose type is an associated type of the generic type T . 如您所见,我使用参数定义泛型函数,该参数的类型是泛型类型 T的关联类型 。 How can I call this function?
我怎么称呼这个功能? I want to use MyClass.ID.one as the argument, but the compiler gives the following warning:
我想使用MyClass.ID.one作为参数,但编译器提供以下警告:
cannot convert value of type 'MyClass.ID' to expected argument type '_.ID'
It appears that Swift has a problem inferring T
from the invocation by starting from MyClass.ID
being T.ID
and backing into MyClass
being T
. 看来Swift通过从
MyClass.ID
开始为T.ID
并且支持MyClass
为T
从调用中推断出T
是一个问题。
If you change your function to take an additional parameter of type T
, the code compiles and runs fine: 如果您更改函数以获取类型
T
的附加参数,则代码将编译并运行正常:
func process<T: B>(_ value: T.ID, _ workaround : T) {
// do something
}
let workaround = MyClass()
process(MyClass.ID.one, workaround)
Swift designers could approach this inference problem in two ways: Swift设计人员可以通过两种方式解决这个推理问题:
T
by enforcing stricter rules on function signatures. T
It appears that they decided on the second approach with Swift 4, because the original function fails to compile, issuing the following error: 看来他们决定使用Swift 4的第二种方法,因为原始函数无法编译,发出以下错误:
generic parameter
'T'
is not used in function signature通用参数
'T'
未在函数签名中使用
A better work-around is to pass the type instead of an instance, using Java-style approach: 更好的解决方法是使用Java风格的方法传递类型而不是实例:
func process<T: B>(_ value: T.ID, _ workaround: T.Type) {
// do something
}
...
process(MyClass.ID.one, MyClass.self)
Note: The edit is based on very insightful comments by tesch 注意:编辑基于tesch非常有见地的评论
dasblinkenlight provides a good answer to why your current implementation doesn't work. dasblinkenlight为您当前实现无效的原因提供了一个很好的答案。 If the decided resolution is to simply find another way to implement this function, then I would opt for a less hacky solution:
如果决定的解决方案是简单地找到另一种方法来实现这个功能,那么我会选择一个不那么hacky的解决方案:
extension B {
static func process(_ value: Self.ID) {
//do stuff
}
}
MyClass.process(.one)
This takes advantage of the more flexible type inference achievable via protocol extension Self
. 这利用了通过协议扩展
Self
实现的更灵活的类型推断。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.