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

如何定义可接收含特定字段任意数据类的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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.09 21:17:47