我对 swift 中的泛型有疑问。让我们公开我的代码。
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
出现错误
无法将类型“AnyFoo”(又名“AnyFoo”)的返回表达式转换为返回类型“AnyFoo”
createTwo
出现错误
无法将类型“AnyFoo”(又名“AnyFoo”)的返回表达式转换为返回类型“AnyFoo”
为什么会出现这种情况。我正在返回正确的值。
和有什么区别createOne
and createTwo
编辑以回应对问题的编辑:
createTwo
不起作用,因为你和我在原来的答案中所说的有同样的误解。createTwo
自己决定F
应该是String
or Int
,而不是“任何符合Fooable
".
For createOne
,你还有另一个常见的误解。泛型类是不变的. AnyFoo<String>
不是一种AnyFoo<Fooable>
。事实上,它们是完全不相关的类型!看here更多细节。
基本上,您尝试做的事情违反了类型安全,因此您重新设计 API 并选择另一种不同的方法。
原始答案(用于问题的初步修改)
您似乎对泛型有一个常见的误解。通用参数由调用者决定,而不是被调用者决定。
In createOne
,你正在返回anyFoo
,其类型为AnyFoo<Int>
, not AnyFoo<P>
。该方法(被调用者)自行决定P
应该Int
。这不应该发生,因为caller决定通用参数应该是什么。如果被调用者是通用的,它必须能够使用any类型(在限制范围内)。反正,P
不可能Int
无论如何,从那时起P: FooProtocol
.
Your createOne
方法根本不应该是通用的,因为它只适用于Int
:
func createOne() -> AnyFoo<Int> {
let anyFoo = AnyFoo(p: FooImpClass())
return anyFoo
}
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)