代码之家  ›  专栏  ›  技术社区  ›  Bitcoin Cash - ADA enthusiast

如何生成不能具体化的递归函数?

  •  2
  • Bitcoin Cash - ADA enthusiast  · 技术社区  · 8 年前

    我想泛化以下函数:

    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中泛化这个函数?

    2 回复  |  直到 8 年前
        1
  •  6
  •   Salem    6 年前

    您可以将递归函数设为非内联函数,并将 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)
    

    不是吗 一个函数-它被直接复制到调用站点。没有函数,没有调用堆栈,没有递归。在这种情况下,你必须通过 而不是使泛型参数具体化,这基本上就是如果需要 instanceof 用泛型参数检查。

    自己动手吧( 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))
                    }
                }
            }
        }
    }
    

        2
  •  0
  •   SOFe    7 年前

    您可以在内联函数中定义函数。

    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)
    }
    

    看到了吗 this working test

    为什么有效:

    • 每次呼叫 execute64 ,一个新的匿名类被内联创建。
    • 匿名类允许我们在函数内定义函数。
    • 我们有一个实际编译的函数(不仅仅是一个内联函数)。所以我们可以递归地调用这个函数,而不必担心内联,因为 inline

    注:

    • execute64()
    • 执行64 调用(但在递归期间不创建新实例)。我不确定这个内联函数是否仍能从内联lambdas中获得性能提升,但它确实解决了 reified .