我有以下类使用通用工厂方法:
final class Something<T> {
let value: T
init(initial: T) {
value = initial
}
}
extension Something {
class func zip<A, B>(a: A, _ b: B) -> Something<(A, B)> {
let initial = (a, b)
return Something<(A, B)>(initial: initial)
}
}
为什么我不能在没有明确指定返回类型的情况下调用zip
?
// ERROR: Cannot invoke `zip` with an argument list of type `(Int, Int)`
let y = Something.zip(1, 2)
// OK: Works but it’s unacceptable to require this on caller's side
let x = Something<(Int, Int)>.zip(1, 2)
感谢您的时间!
答案 0 :(得分:2)
你看到这个的原因是这次电话没有任何内容:
let y = Something.zip(1, 2)
告诉Swift T
应该是什么。
您的调用隐式指定A
和B
应该是什么,并指定方法应返回Something<A, B>
。但Something<A, B>
未与Something<T>
相关联。
事实上,您的通话中没有任何内容与T
相关联; T
未指定,因此它可以是任何内容。我的意思是字面意思 - 你实际上可以在Something
之后将(几乎)任意随机类型放在尖括号中并且它将完全相同:
let y = Something<UICollectionViewDelegateFlowLayout>.zip(1, 2)
你真正想做的是以某种方式指定T
必须是元组,并且这两个参数与元组元素的类型相同。不幸的是,Swift目前还没有正确执行此操作所需的功能。如果语言更复杂,你可以这样说:
extension<A, B> Something where T == (A, B) {
class func zip(a: A, _ b: B) -> Something {
let initial = (a, b)
return Something(initial: initial)
}
}
但是现在,你将不得不处理这个可怕的黑客攻击,它通过毫无意义地重用T
类型参数来使其不再处于松散状态:
extension Something {
class func zip<B>(a: T, _ b: B) -> Something<(T, B)> {
let initial = (a, b)
return Something<(T, B)>(initial: initial)
}
}
答案 1 :(得分:1)
简而言之,您使用泛型不正确。它不是实时功能,它是预编译的东西。如果您需要从通用输入值中创建抽象类,请查看并执行以下操作:
class Abstract<T> {
init(value: T) {
print("inputed value: \(value)")
}
}
class Something {
class func zip<A, B>(value: A, value2: B) -> Abstract<(A, B)> {
print("Something.zip", value, value2)
return Abstract<(A, B)>(value: (value, value2))
}
}
Something.zip(5, value2: 40) // "inputed value: (5, 40)"
答案 2 :(得分:0)
T
以这种方式与A
和B
无关,因此无法推断。
例如
let z = Something<(String, String)>.zip(1, 2)
let z2 = Something<AnyObject>.zip(1, 2)
可以正常工作以返回Something<(Int, Int)>