Kotlin工厂与泛型的界面

我在我的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>>并返回一个TypeToken<List<T>>的工厂,就会TypeToken<List<T>> ,因为我没有地方放这个T参数。

我渴望听到你的建议。

我自己找到解决方案,使用invoke操作符的乐趣,我张贴在我原来的问题,我可以写下面的内容:

 private class ListResultMapper<out E>(private val elementMapper: ResultMapper<E>) : ResultMapper<List<E>> { /* ... */ } val listMapperFactory = ResultMapperFactory<List<*>> { type, context -> context.resultMapperFactory.get(type.elementType(), context)?.let { ListResultMapper(it) } }