You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何使用Kotlin成员引用生成属性的层级路径字符串

解决方案:用Kotlin成员引用生成属性层级路径

问题原因

你之前的Builder写法出错,是因为试图通过KClass获取属性引用——it::propC里的it是KClass<B>,但propC是B类的成员,不是KClass<B>的成员,所以编译器无法识别。

方案一:改进Builder类

重新设计Builder,让它直接接收属性引用,而非通过KClass间接获取:

data class A(val propB: B)
data class B(val propC: C)
data class C(val propD: D, val propE: E)
data class D(val value: String)
data class E(val value: Int)

class RefBuilder<R : Any>(private val pathSegments: List<String>) {
    companion object {
        // 从根属性初始化Builder
        inline fun <T, reified R : Any> from(prop: KProperty1<T, R>): RefBuilder<R> {
            return RefBuilder(listOf(prop.name))
        }
    }

    // 添加下一层属性引用,返回新的Builder
    inline fun <reified N : Any> add(prop: KProperty1<R, N>): RefBuilder<N> {
        return RefBuilder(pathSegments + prop.name)
    }

    // 生成最终路径字符串
    fun build(): String = pathSegments.joinToString(".")
    override fun toString(): String = build()
}

fun main() {
    val path1 = RefBuilder.from(A::propB)
        .add(B::propC)
        .add(C::propD)
        .toString()
    println(path1) // 输出: propB.propC.propD

    val path2 = RefBuilder.from(A::propB)
        .add(B::propC)
        .add(C::propE)
        .toString()
    println(path2) // 输出: propB.propC.propE
}

方案二:更简洁的函数组合(推荐)

定义一个infix函数,直接组合属性引用,通过name获取路径:

data class A(val propB: B)
data class B(val propC: C)
data class C(val propD: D, val propE: E)
data class D(val value: String)
data class E(val value: Int)

// 组合两个属性引用,生成包含层级路径的新属性引用
infix fun <T, R, N> KProperty1<T, R>.then(next: KProperty1<R, N>): KProperty1<T, N> {
    return object : KProperty1<T, N> {
        override val name: String = "${this@then.name}.${next.name}"
        override val returnType: KType = next.returnType
        override val annotations: List<Annotation> = emptyList()
        override val isLateinit: Boolean = false
        override val isConst: Boolean = false
        
        // 保留属性的实际取值逻辑(可选,如果你需要同时支持取值)
        override fun getValue(thisRef: T, property: KProperty<*>): N {
            val intermediate = this@then.getValue(thisRef, property)
            return next.getValue(intermediate, property)
        }
    }
}

fun main() {
    val path1 = (A::propB then B::propC then C::propD).name
    println(path1) // 输出: propB.propC.propD

    val path2 = (A::propB then B::propC then C::propE).name
    println(path2) // 输出: propB.propC.propE
}

这个方案更简洁,直接通过链式调用then组合属性引用,获取name就是你要的层级路径,同时还保留了属性的取值能力(如果需要的话)。

核心优势

两种方案都能在编译时检查属性的合法性,当属性重命名时,IDE会自动重构路径字符串,完全避免硬编码的维护问题。

内容的提问来源于stack exchange,提问作者fiftyone_51

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.20 05:10:32