上课:
abstract class Bird<T: Food>
和一个子类,Fish
扩展Food
:
class Falcon: Bird<Fish>()
如何创建返回Bird
的方法:
fun getBird(type: Int): Bird<Food> {
if (type == SOME_CONSTANT) {
return Falcon()
} else {
// Another bird
}
}
获得:
Type mismatch: Required Bird<Food>, found Falcon
答案 0 :(得分:1)
你基本上有两个选择来解决这个问题:
使用声明网站差异。如果可能,这是首选。
您需要使用Bird<Fish>
(您的Falcon
)作为Bird<Food>
的子类型(您正在返回)。由于Fish
也是Food
的子类型,因此您需要的是协方差,您可以使用out
关键字为type参数指定:
abstract class Bird<out T: Food>
现在,您已在评论中添加了以下基类中具有T?
类型的可变属性的内容,例如:
abstract class Bird<out T: Food> {
var food: T? = null
}
这是声明网站差异的问题。如果你想要协方差工作,那么type参数只能出现在out
位置的类中,这意味着你可以拥有返回T
的函数,但你不能拥有接受T
的函数。 (在这种情况下,这将是属性的setter)。想一想:如果您引用Falcon
作为Bird<Food>
,因为您是从getBird
函数获得的,那么您可以突然将其Food
提供给所有Fish
,而不仅仅是T?
Bird<out Food>
。这会打破类型安全。这让我们得到了另一个解决方案...
使用使用网站差异。
这不太理想,但有时是必要的(就像你的情况一样,因为基类中fun getBird(type: Int): Bird<out Food>
类型的可变属性。此解决方案归功于@tynn's very good answer,但让我扩展它。
通过使函数返回T
,您可以仅在函数的返回类型而不是整个抽象类上标记协方差。
in
这样做可以让您在班级的out
和T
位置获得in
参数,但会阻止您使用Bird
的所有功能(您从getBird
函数获取的println(getBird(1).food)
个实例上的newFood
位置。
所以你可以在改变之后做到这一点:
null
但是Nothing?
的任何值都不是getBird(1).food = newFood
,因为这里需要food
类型的变量,only null
is}:
Bird
这种无法设置函数返回的barTintColor
import UIKit
extension UIToolbar {
func setBackgroundColor(image: UIImage) {
setBackgroundImage(image, forToolbarPosition: .any, barMetrics: .default)
}
}
属性的限制就是“恢复”类型安全性。
答案 1 :(得分:1)
您必须在out
getBird()
方差
fun getBird(type: Int): Bird<out Food>
像这样你可以在没有改变Bird
类的情况下返回任何食物来源的鸟类。