对于 Swift 方法参数,将非泛型 ObjC 类 向上转换为父 class
Upcast non-generic ObjC Classes to parent class for Swift method parameter
我在 Objective-C
中定义了一些与此类似的 classes:
@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
的任何子 class。我尝试了以下方法:
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
。
一般来说,我想要一种方法可以处理任何类型的子父 class(SubParent1
、SubParent2
),它具有父 class 的子类型type (SubType1
, SubType2
) 因为该方法只需要访问 Parent
上定义的属性。由于某些其他限制,切换 Objective-C
classes 不是一个可行的选项,因此我正在寻找一种解决方案,以保持 Objective-C
中定义的 classes。不确定是否可能,但如果可能的话,如果参数预期为 Parent
?
,我可以在之后向下转换吗?
稍后编辑:此外,我如何允许函数 return Swift 中的任何子父类型,例如:
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
和 sub2
'Type of expression is ambiguous without more context'。
这里的问题是您期望协变,但是 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
.
上通用
您正在对 Parent
而不是 Type
进行参数化,而您实际上正在更改的是 Type
。你的意思是:
func callFunc<T>(parent: Parent<T>) { ... }
虽然您可以显式调用 T: Type
,但这并不是真正必要的,因为父级已经强制执行了。
我在 Objective-C
中定义了一些与此类似的 classes:
@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
的任何子 class。我尝试了以下方法:
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
。
一般来说,我想要一种方法可以处理任何类型的子父 class(SubParent1
、SubParent2
),它具有父 class 的子类型type (SubType1
, SubType2
) 因为该方法只需要访问 Parent
上定义的属性。由于某些其他限制,切换 Objective-C
classes 不是一个可行的选项,因此我正在寻找一种解决方案,以保持 Objective-C
中定义的 classes。不确定是否可能,但如果可能的话,如果参数预期为 Parent
?
稍后编辑:此外,我如何允许函数 return Swift 中的任何子父类型,例如:
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
和 sub2
'Type of expression is ambiguous without more context'。
这里的问题是您期望协变,但是 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
.
您正在对 Parent
而不是 Type
进行参数化,而您实际上正在更改的是 Type
。你的意思是:
func callFunc<T>(parent: Parent<T>) { ... }
虽然您可以显式调用 T: Type
,但这并不是真正必要的,因为父级已经强制执行了。