问题描述
我很快就遇到了泛型的问题.让我们公开我的代码.
I have a problem with generics in swift. Let's expose my code.
protocol FooProtocol {
associatedtype T
}
protocol Fooable { }
extension Int : Fooable { }
extension String: Fooable { }
class AnyFoo<T>: FooProtocol {
init<P: FooProtocol>(p: P) where P.T == T { }
}
class FooIntImpClass: FooProtocol {
typealias T = Int
}
class FooStringImpClass: FooProtocol {
typealias T = String
}
func createOne(isInt: Bool) -> AnyFoo<Fooable> {
if isInt {
let anyFoo = AnyFoo(p: FooIntImpClass())
return anyFoo
} else {
let anyFoo = AnyFoo(p: FooStringImpClass())
return anyFoo
}
}
func createTwo<F: Fooable>(isInt: Bool) -> AnyFoo<F> {
if isInt {
let anyFoo = AnyFoo(p: FooIntImpClass())
return anyFoo
} else {
let anyFoo = AnyFoo(p: FooStringImpClass())
return anyFoo
}
}
createOne
出现错误
createTwo
出现错误
为什么会这样.我返回的是正确的值.
Why is this happening. I'm returning the correct value.
与createOne
和createTwo
推荐答案
编辑以答复对问题的
createTwo
不起作用,因为您的误解与我在原始答案中所说的相同. createTwo
独自决定F
应该是String
或Int
,而不是任何符合Fooable
的类型".
createTwo
doesn't work because you have the same misconception as I said in my original answer. createTwo
decided on its own that F
should be either String
or Int
, rather than "any type that conforms to Fooable
".
对于createOne
,您还有另一个常见的误解. 通用类是不变的. AnyFoo<String>
不是AnyFoo<Fooable>
的一种.实际上,它们是完全无关的类型!有关更多详细信息,请参见此处.
For createOne
, you have another common misconception. Generic classes are invariant. AnyFoo<String>
is not a kind of AnyFoo<Fooable>
. In fact, they are totally unrelated types! See here for more details.
基本上,您尝试执行的操作违反了类型安全性,因此您重新设计了API,并选择了另一种不同的方法.
Basically, what you are trying to do violates type safety, and you redesign your APIs and pick another different approach.
原始答案(用于问题的初始修订)
Original answer (for initial revision of question)
您似乎对泛型有一个普遍的误解. 通用参数由调用者而不是被调用者决定.
You seem to be having a common misconception of generics. Generic parameters are decided by the caller, not the callee.
在createOne
中,您将返回类型为AnyFoo<Int>
而不是AnyFoo<P>
的anyFoo
.方法(被调用方)已自行决定P
应该为Int
.这不应该发生,因为 caller 决定应该使用什么通用参数.如果被调用方是通用的,则它必须能够使用 any 类型(在约束内).无论如何,由于P: FooProtocol
,所以P
不能再是Int
.
In createOne
, you are returning anyFoo
, which is of type AnyFoo<Int>
, not AnyFoo<P>
. The method (callee) have decided, on its own, that P
should be Int
. This shouldn't happen, because the caller decides what generic parameters should be. If the callee is generic, it must be able to work with any type (within constraints). Anyway, P
can't be Int
here anyway, since P: FooProtocol
.
您的createOne
方法根本不应该是通用的,因为它仅适用于Int
:
Your createOne
method should not be generic at all, as it only works with Int
:
func createOne() -> AnyFoo<Int> {
let anyFoo = AnyFoo(p: FooImpClass())
return anyFoo
}
这篇关于在带有Swift的函数中使用类型擦除返回通用类型(无法转换类型的返回表达式…)的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!