kFunction1中的kotlin泛型

时间:2016-03-22 13:01:55

标签: generics kotlin

假设您有两个类TestA和TestB。假设TestA扩展了TestB:

public class TestB {
    private int intProp;
    public int getIntProp() {
        return intProp;
    }
    public void setIntProp(int intProp) {
        this.intProp = intProp;
    }
}


public class TestA extends TestB {
    private String strProp;
    public String getStrProp() {
        return strProp;
    }
    public void setStrProp(String strProp) {
        this.strProp = strProp;
    }
}

现在我创建下一行代码:

var getter1: KFunction1<TestA, Int> = TestA::getIntProp

如您所见,我从TestB的TestA类方法访问:TestA :: getIntProp 结果是具有通用参数的KFunction1的实例&lt; TestA,Int&gt;

现在我尝试创建下一行代码

var getter2: KFunction1<TestA, Int> = TestB::getIntProp

它也可以工作和编译,而我希望会有编译错误

1 个答案:

答案 0 :(得分:5)

这是generics variance in Kotlin,其目的是在具有类层次结构的参数的泛型类上强加类型安全层次结构。

KFunction1的通用参数定义为<in P1, out R>P1定义为in修饰符,R定义为out修饰符。这意味着将会:

  • P1修饰符引入的 in的逆转。

    如果KFunction1<PSuper, R>KFunction1<P, R>的超类型,则任何PSuper都将是P的子类型。但是会增加限制,P1只能作为(传入)KFunction1成员的参数出现。

  • R修饰符引入的 out的协方差。

    如果KFunction1<P, RSub>KFunction1<P, R>的子类型,则任何RSub都是R的子类型。此处R将受到限制:它只能用作KFunction1成员的返回值(已通过)。

因此,您可以将KFunction1<PSuper, RSub>分配给KFunction1<P, R>类型的变量。

这对KFunction1有意义,因为任何接收类型为PSuper的参数的函数也可以接收P的实例(但反之亦然),以及任何返回的函数RSub的实例同时返回R的实例(但反之亦然)。

您只需撰写一个显示此行为的示例:

class Invariant<T>  {
    fun f(i: Int): T { throw Exception() } // OK
    fun f(t: T): Int { throw Exception() } // OK
}

class Contravariant<in T> {
    fun f(i: Int): T { throw Exception() } // error, T cannot be returned
    fun f(t: T): Int { throw Exception() } // OK, T is parameter type
}

class Covariant<out T> {
    fun f(i: Int): T { throw Exception() } // OK, T is returned
    fun f(t: T): Int { throw Exception() } // error, T cannnot be parameter type
}

open class Base
class Derived: Base()

val i1: Invariant<Base> = Invariant<Derived>() // error
val i2: Invariant<Derived> = Invariant<Base>() // error

val n1: Contravariant<Base> = Contravariant<Derived>() // error
val n2: Contravariant<Derived> = Contravariant<Base>() // OK

val v1: Covariant<Base> = Covariant<Derived>() // OK
val v2: Covariant<Derived> = Covariant<Base>() // error