【发布时间】:2025-12-06 23:45:01
【问题描述】:
我的 Kotlin 代码中有一个工厂接口,就像这样(使用 Guava 的 TypeToken):
interface ResultMapperFactory {
fun <T> get(type: TypeToken<T>, context: MapperLookupContext): ResultMapper<T>?
}
到目前为止,一切都很好。这在调用它时非常容易使用,但是实现几乎总是需要不安全的强制转换:
object StringFactory : ResultMapperFactory {
override fun <T> get(type: TypeToken<T>, context: MapperLookupContext): ResultMapper<T>? {
return if (type.rawType == String::class.java) MyStringMapper as ResultMapper<T> else null
}
}
这很难看,但我用一个绝妙的技巧克服了它。首先,一个用于创建TypeToken 实例的实用函数:
inline fun <reified T> typeToken(): TypeToken<T> = object : TypeToken<T>() {}
现在我在我的工厂接口中添加了一个伴随对象:
companion object {
inline operator fun <reified R> invoke(crossinline body: (TypeToken<R>, MapperLookupContext) -> ResultMapper<R>?): ResultMapperFactory {
val t = typeToken<R>().type
return object : ResultMapperFactory {
override fun <T> get(type: TypeToken<T>, context: MapperLookupContext): ResultMapper<T>? {
return if (type.isSubtypeOf(t)) body(type as TypeToken<R>, context) as ResultMapper<T>? else null
}
}
}
}
这使我可以在一个地方进行未经检查(但安全)的转换,我可以编写如下代码:
val stringMapper: ResultMapper<String> = TODO()
val stringMapperFactory = ResultMapperFactory<String> { type, context ->
stringMapper
}
但是,一旦我想实现一个接受 TypeToken<List<T>> 并返回 ResultMapper<List<T>> 的工厂,这种方法也会崩溃,因为我没有地方可以放置 T 参数。
我很想听听你的建议。
【问题讨论】:
-
你的意思是
T不是具体类型? -
没错。我想写一个工厂,为
List<T>为任何T创建一个映射器。这是可能的,因为工厂可以查找如何将T类型的元素映射到MapperLookupContext。