如何定义可接收含特定字段任意数据类的Kotlin函数?
在Kotlin中模拟TypeScript结构类型实现需求
因为Kotlin是标称类型系统,不支持TypeScript那样的原生结构类型约束,但可以通过以下几种方式实现你的需求,无需修改外部包中的A和B类:
方法1:接口+扩展转换(最稳妥)
先定义一个包含目标属性的接口,再给外部类添加扩展函数转换为该接口实例:
// 定义统一的接口 interface HasP { val p: Int } // 给外部类A添加转换扩展 fun A.asHasP(): HasP = object : HasP { override val p: Int get() = this@asHasP.p } // 给外部类B添加转换扩展 fun B.asHasP(): HasP = object : HasP { override val p: Int get() = this@asHasP.p } // 定义foo函数接收HasP类型 fun foo(x: HasP) { // 可以直接访问p属性 println("p的值是:${x.p}") }
调用示例:
val a = A(10, 20) val b = B(30, 40) foo(a.asHasP()) foo(b.asHasP())
方法2:inline+reified泛型(最贴近TS写法)
利用Kotlin的内联函数和具体化类型,在编译期检查类型是否包含目标属性,无需显式转换:
inline fun <reified T> foo(x: T) { // 编译期验证T是否有p属性,否则报错 val pValue = x::p.get() println("p的值是:$pValue") }
调用示例:
foo(A(10, 20)) // 编译通过,A有p属性 foo(B(30, 40)) // 编译通过,B有p属性 // foo(OtherClass()) // 编译报错,因为OtherClass没有p属性
这种方式的优势是调用时无需额外转换,完全贴近TypeScript的写法,但依赖编译期类型检查,仅适用于编译时能确定类型的场景。
方法3:通用包装类(扩展性更强)
如果后续还有更多类似的外部类需要支持,可以用通用包装类统一处理:
interface HasP { val p: Int } // 通用包装类,接收任意对象和属性获取逻辑 class HasPWrapper<T>(private val target: T, private val pGetter: (T) -> Int) : HasP { override val p: Int get() = pGetter(target) } // 简化包装的扩展函数 fun A.toHasP() = HasPWrapper(this) { it.p } fun B.toHasP() = HasPWrapper(this) { it.p } fun foo(x: HasP) { println("p的值是:${x.p}") }
调用方式和方法1一致,后续新增外部类时,只需要添加对应的扩展函数即可。
内容的提问来源于stack exchange,提问作者tamuhey
相关产品推荐
相关产品推荐

