以类型安全和符合人体工程学的方式访问通用异构集合



目标是将通用对象(不同类型参数(的列表存储在列表中,并以类型安全且符合人体工程学的方式对其进行操作。

我目前的设计使用访客模式:

sealed interface Element {
fun visit(visitor: Visitor)
}
interface Visitor {
fun <T> accept(elementA: ElementA<T>)
}
data class ElementA<T>(
// example members, many more in the real code
val produce : () -> T,
val doSomething: (T) -> Unit
) : Element {
override fun visit(visitor: Visitor) = visitor.accept(this)
}

尽管如此,访问者写起来不是很方便,因为必须将Visitor:子类化

fun exampleUse(elements: List<Element>) {
for (element in elements) {
element.visit(object : Visitor {
override fun <T> accept(elementA: ElementA<T>) {
// We don't care about the actual type T, just that it exists
elementA.doSomething(elementA.produce())
}
})
}
}

它不是很符合人体工程学,我希望用户只需要编写传统的短代码,比如CCD_ 2。

唯一的要求是:

  • 元素应该可以存储在列表中(同构集合(
  • 用法(例如:a.doSomething(a.produce())(应该与类分开,因为它们是在具有不同关注点的不同包中定义的

如果有办法避免访客的样板,那就更好了。

这似乎满足了您的要求(我假设Element仅作为所有ElementA<Something>的公共超类型存在(:

data class ElementA<T>(
// example members, many more in the real code
val produce : () -> T,
val doSomething: (T) -> Unit
)
// optional
typealias Element = ElementA<*>
// or fun exampleUse(elements: List<ElementA<*>>)
// if you don't create Element
fun exampleUse(elements: List<Element>) {
fun <T> use(elementA: ElementA<T>) {
// We don't care about the actual type T, just that it exists
elementA.doSomething(elementA.produce())
}

for (element in elements) {
use(element)
}
}

注意,本地函数也可以是扩展函数:

fun exampleUse(elements: List<Element>) {
fun <T> ElementA<T>.use() {
// We don't care about the actual type T, just that it exists
doSomething(produce())
}

for (element in elements) {
element.use()
}
}

我不确定这是否符合您的要求,但我在Kotlin中实现了一个类型安全的异构映射:https://github.com/broo2s/typedmap。它与您的示例有点不同,因为它不是列表,而是地图。你可以这样使用它:

val map = simpleTypedMap()
sess += User("alice")
val user = sess.get<User>()

每个密钥类型仍然可以存储多个项目,但由于这是一个映射,每个项目都必须是唯一可识别的,所以我不确定这是否适合你:

map[UserKey(1)] = User("alice")
map[UserKey(2)] = User("bob")
val alice = map[UserKey(1)]
val bob = map[UserKey(2)]

相关内容

  • 没有找到相关文章

最新更新