协变 vs 逆变
@interface RACCommand<__contravariant InputType, __covariant ValueType> : NSObject
可以看到这样的定义协变(covariance)和逆变(contravariance)在 Objective-C 泛型中并不十分常见,但它们是理解类型系统中的灵活性和安全性的重要概念。以下是协变和逆变的概念和示例:
协变(Covariance)
协变允许将子类对象赋值给父类泛型对象(从具体到通用)。这在返回类型中尤其有用,因为可以向上兼容。例如,如果我们有一个 RACSignal 类的子类 RACSubject,协变可以让 RACSignal<NSString *> 赋值给 RACSignal<id>。
@interface RACSignal<__covariant ValueType> : NSObject
@end
RACSignal<NSString *> *stringSignal = [[RACSignal alloc] init];
RACSignal<id> *anySignal = stringSignal; // 合法,因为 RACSignal 是协变的这里,通过使用 __covariant,RACSignal 能够将 RACSignal<NSString *> 赋值给 RACSignal<id>,保证类型的灵活性。
逆变(Contravariance)
逆变允许将父类泛型对象赋值给子类泛型对象(从通用到具体)。在 Objective-C 中使用 __contravariant 让泛型参数接受更广泛的类型,主要用于参数类型。例如:
@interface MyHandler<__contravariant InputType> : NSObject
- (void)handle:(InputType)input;
@end在上面的代码中,MyHandler 的泛型参数 InputType 使用了 __contravariant,因此可以传递更广泛的类型作为参数:
MyHandler<id> *objectHandler = [[MyHandler alloc] init];
MyHandler<NSString *> *stringHandler = objectHandler; // 合法,逆变允许更具体的类型
[stringHandler handle:@"Hello, world!"];这里,逆变使得 MyHandler<id> 可以赋值给 MyHandler<NSString *>,所以我们能够创建一个接受 id 类型的处理器,并将其传递给一个期待 NSString 类型的处理器。
总结
- 协变 ( - __covariant):用于返回类型,使子类泛型可以赋值给父类泛型。
- 逆变 ( - __contravariant):用于参数类型,使父类泛型可以赋值给子类泛型。
在实际开发中,协变和逆变让代码更灵活并提高了类型安全性。
Last updated