问题描述
我在 Objective-C
中定义了一些与此类似的类:
@interface Type: NSObject {
}
@end
@interface SubType1: Type {
}
@end
@interface SubType2: Type {
}
@end
@interface Parent <T: __kindof Type *> : NSObject
@property (nonatomic,strong) NSArray <T> *anArray;
@property (nonatomic,strong) T anObject;
@end
@interface SubParent1: Parent<SubType1 *> {
}
@end
@interface SubParent2: Parent<SubType2 *> {
}
@end
我正在尝试创建一个 Swift
函数,它可以采用 Parent
的任何子类。我尝试了以下方法:
func callFunc(parent: Parent<Type>) {
}
callFunc(parent: SubParent1())
我收到错误:Cannot convert value of type 'Parent<SubType1> to expected argument type 'Parent<Type>'
也试过了:
func callFunc<T>(parent: T) where T: Parent<Type>{
}
callFunc(parent: SubParent1())
我收到错误 Type of expression is ambiguous without more context
。
一般来说,我想要一种可以处理任何类型的子父类 (SubParent1
,SubParent2
) 的方法,它具有父类类型 (SubType1
,{{ 1}}),因为该方法只需要访问在 SubType2
上定义的属性。由于其他一些限制,无法切换 Parent
类,因此我正在寻找一种解决方案,以保留 Objective-C
中定义的类。不确定是否可能,但如果可能的话,如果参数预期为 Objective-C
,我之后是否可以向下转型?
稍后编辑:另外,我如何允许函数返回 Swift 中的任何子父类型,例如:
Parent
编译器抱怨 enum AnEnum {
case subParent1(_ : SubParent1)
case subParent2(_ : SubParent2)
func subParent<T: Type>() -> Parent<T>? {
switch self {
case .subParent1(let sub1):
return sub1
case .subParent2(let sub2):
return sub2
}
}
}
和 sub1
'表达式类型不明确,没有更多上下文'。
解决方法
您在 Parent
而不是 Type
上进行参数化,您实际上正在更改它。你的意思是:
func callFunc<T>(parent: Parent<T>) { ... }
虽然您可以明确调用 T: Type
,但这并不是真正必要的,因为 Parent 已经强制执行了。
这里的问题是您期望协方差,但 Swift 泛型通常不支持协方差。
关于协方差的解释网上有很多,这里就不解释了。但是我将确切地展示协方差如何与您的示例类型不符。考虑以下代码:
let sp1 = SubParent1()
let p = sp1 as Parent<Type> // (1) Swift forbids this cast...
let t: Type = SubType2()
p.anObject = t // (2) ...because this assigment would be unsound.
假设 Swift 允许了被禁止的类型转换 (1)。然后赋值 (2) 会将 SubType2
分配给只能包含 SubType1
的属性。
您可以通过使 callFunc
函数在 Parent
子类型和 Type
子类型上通用来解决此问题:
func callFunc<T,P>(parent: P) where T: Type,P: Parent<T> { }
编辑:Rob Napier 的回答正确地表明您只需要在 T
上通用,而不是在 P
上。