创建返回泛型参数化类的方法

时间:2018-03-20 05:01:49

标签: kotlin

上课:

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  

2 个答案:

答案 0 :(得分:1)

你基本上有两个选择来解决这个问题:

  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>。这会打破类型安全。这让我们得到了另一个解决方案...

  2. 使用使用网站差异。

    这不太理想,但有时是必要的(就像你的情况一样,因为基类中fun getBird(type: Int): Bird<out Food> 类型的可变属性。此解决方案归功于@tynn's very good answer,但让我扩展它。

    通过使函数返回T,您可以仅在函数的返回类型而不是整个抽象类上标记协方差。

    in

    这样做可以让您在班级的outT位置获得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类的情况下返回任何食物来源的鸟类。