带有异构容器的Kotlin泛型

ma8fv8wu  于 2023-10-23  发布在  Kotlin
关注(0)|答案(1)|浏览(113)

假设我有一个异构的map容器,其中键包含值的类型信息:

interface Container<K : Container.Key<*>> {
    interface Key<V>
    
    interface Entry<K : Key<V>, V>
}

我想有一个类似于get()的函数,

fun <V> get(key: Key<V>): V?

但也要将此函数限制为我们的类型参数K--其想法是,实现Container的类也可能具有其自定义键类型Container.Key<V>,因此我们希望get()的输入参数为Container.Key<V>
这在Kotlin中可以表达吗?

anauzrmj

anauzrmj1#

不,这是不可能的(还没有)。
你基本上想要:

fun <V, TKey: K & Key<V>> get(key: TKey): V?

也就是说,get应该接受一个既是K又是Key<V>的东西。不幸的是,这种类型的交叉口还没有可用。
Kotlin只支持T & Any形式的交集类型,其中T是一个可空的类型参数,以表示“T的不可空版本”。
关于添加更好的交叉类型支持,有一个冗长的讨论here
所以现在,您只能在运行时强制执行TKey: K & Key<V>。取两个参数-KKey<V>。强调它们是同一个对象。

// users would call this by passing the same thing twice
fun <V> get(key1: K, key2: Key<V>): V?

在实现中,您应该检查key1 === key2
请注意,我们不能在运行时检查一个键是否确实是Key<V>而不是Key<SomethingElse>,因为V被擦除了。你可以使用KClass<V>来解决这个问题,但是如果V本身是参数化的,那么这就不好用了。
如果这对你来说没问题,并且你的Key接口有办法告诉你它是否是Key<V>,给定一个KClass<V>,你可以使用这样的签名:

fun <V> get(key: K, clazz: KClass<V>): V?
// in the implementation, check if key is Key<V>, using members of Key<*> and clazz

相关问题