如何使用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
相关产品推荐
相关产品推荐

