问题 Kotlin属性:“属性的类型参数必须在其接收器类型中使用”


我有以下简单的Kotlin扩展功能:

// Get the views of ViewGroup
inline val ViewGroup.views: List<View>
    get() = (0..childCount - 1).map { getChildAt(it) }

// Get the views of ViewGroup of given type
inline fun <reified T : View> ViewGroup.getViewsOfType() : List<T> {
    return this.views.filterIsInstance<T>()
}

此代码编译并正常工作。但是,我想要这个功能 getViewsOfType 成为一个财产,就像 views。 Android Studio甚至建议它。我让AS进行重构,它会生成以下代码:

inline val <reified T : View> ViewGroup.viewsOfType: List<T>
    get() = this.views.filterIsInstance<T>()

但是这段代码没有编译。它会导致错误:“属性的类型参数必须在其接收器类型中使用”

这是什么问题?搜索有关此错误的帮助似乎不会导致答案。


1160
2018-05-25 13:34


起源



答案:


如果您在接收器类型中使用所述类型(您正在扩展的类型),则该错误意味着您只能为扩展属性使用泛型类型参数。

例如,您可以扩展一个扩展名 T

val <T: View> T.propName: Unit
    get() = Unit

或者扩展使用类型的那个 T 作为参数:

val <T: View> List<T>.propName: Unit
    get() = Unit

至于为什么会这样,我认为原因是属性不能像函数一样具有泛型类型参数。虽然我们可以使用泛型类型参数调用函数...

val buttons = viewGroup.getViewsOfType<Button>()

...我不相信属性存在类似的语法:

val buttons = viewGroup.viewsOfType<Button> // ??

11
2018-05-25 13:51



是的我觉得这是对的。事实上,当这样思考时,我的 getViewOfType 函数是没用的,因为Kotlin已经有了一种按类型过滤集合的方法。 - Greg Ennis


答案:


如果您在接收器类型中使用所述类型(您正在扩展的类型),则该错误意味着您只能为扩展属性使用泛型类型参数。

例如,您可以扩展一个扩展名 T

val <T: View> T.propName: Unit
    get() = Unit

或者扩展使用类型的那个 T 作为参数:

val <T: View> List<T>.propName: Unit
    get() = Unit

至于为什么会这样,我认为原因是属性不能像函数一样具有泛型类型参数。虽然我们可以使用泛型类型参数调用函数...

val buttons = viewGroup.getViewsOfType<Button>()

...我不相信属性存在类似的语法:

val buttons = viewGroup.viewsOfType<Button> // ??

11
2018-05-25 13:51



是的我觉得这是对的。事实上,当这样思考时,我的 getViewOfType 函数是没用的,因为Kotlin已经有了一种按类型过滤集合的方法。 - Greg Ennis