我想泛化以下功能:
fun ViewGroup.allRadioButtons(f: (RadioButton) -> Unit){
this.afterMeasured {
for(i in 0 until childCount){
val child = getChildAt(i)
if(child is RadioButton){
f(child)
}
if(child is ViewGroup){
child.allRadioButtons(f)
}
}
}
}
因此,我希望使用通用的RadioButton
,而不是对T
进行硬编码,如下所示:
inline fun <reified T> ViewGroup.allViewsOfTypeT(f: (T) -> Unit){
this.afterMeasured {
for(i in 0 until childCount){
val child = getChildAt(i)
if(child is T){
f(child)
}
if(child is ViewGroup){
child.allRadioButtons(f)
}
}
}
}
我无法执行上述操作,因为递归函数中不允许使用类型化的类型。
如何在Kotlin中泛化该功能?
答案 0 :(得分:4)
您可以使递归函数成为非内联函数,并使用表示所需类型的KClass
并附加一个包装函数:
fun <T : View> ViewGroup.allViewsOfTypeT(type: KClass<T>, f: (T) -> Unit) {
afterMeasured {
for (i in 0 until childCount) {
val child = getChildAt(i)
if (type.isInstance(child)) f(child)
if (child is ViewGroup) child.allViewsOfTypeT(type, f)
}
}
}
inline fun <reified T : View> ViewGroup.allViewsOfTypeT(f: (T) -> Unit)
= allViewsOfTypeT(T::class, f)
您不能内联递归函数,除非您可以将其展开为循环,因为内联函数意味着编译后不再是函数-而是直接将其复制到呼叫站点。没有功能,没有调用堆栈,没有递归。在这些情况下,您必须传递KClass
而不是对通用参数进行修饰,这基本上就是您需要使用通用参数进行instanceof
检查时在Java中所做的事情。>
但是,您可以滚动自己的堆栈(Way to go from recursion to iteration):
inline fun <reified T : View> ViewGroup.allViewsOfTypeT(action: (T) -> Unit) {
val views = Stack<View>()
afterMeasured {
views.addAll((0 until childCount).map(this::getChildAt))
}
while (!views.isEmpty()) {
views.pop().let {
if (it is T) action(it)
if (it is ViewGroup) {
afterMeasured {
views.addAll((0 until childCount).map(this::getChildAt))
}
}
}
}
}
我还没有测试过,但是总体思路应该可行。
答案 1 :(得分:0)
您可以在内联函数中定义一个函数。
inline fun <reified T> execute64(crossinline run: (Class<*>, Int) -> Unit) {
var cnt = 0
val x = object : Consumer<Int> {
override fun accept(i: Int) {
if(i > 1) {
repeat(2) { accept(i shr 1) }
return
}
run(T::class.java, cnt++)
}
}
x.accept(64)
}
请注意,它不需要尾部递归,即使用NP硬递归算法也可以使用。
为什么起作用:
execute64
时,都会内联创建一个新的匿名类。inline
d范围不在此函数的范围之内。注意:
execute64()
时都定义一个新的匿名类。因此,如果您的代码中有100个直接调用此函数的位置,则将创建100个匿名类。您的代码可能会遇到类加载缓慢的问题。 (需要引用,我不是类加载专家)execute64
时实例化一个实例(但在递归过程中不会创建新实例)。我不确定此内联函数是否仍能通过内联lambda获得性能提升,但可以肯定地解决了reified
的问题。