实体类型参数和内部函数

我有一个泛型函数,需要实例化其泛型参数的对象,并将其传递给某个接口的实例。
据我所知,实例化该通用对象的唯一方法是使该函数内联并且对该类型参数进行重写。 但是我不想公开这个接口的实现。
问题是内联函数不能使用内部类。

我基本上想要的是这样的:

/* The interface I want to expose */ interface Params<T> { val doc: T } /* The implementation I do not want to expose */ internal class ParamsImpl<T> (override val doc: T) : Params<T> /* The function */ inline fun <reified T> doSomething(init: Params<T>.() -> Unit) { val doc= T::class.java.newInstance() val params = ParamsImpl(doc) // Can't compile since ParamsImpl is internal params.init() } 

你可以通过添加一个中介方法来创建你的ParamsImpl实例来解决这个问题:

 fun <T> createImpl(doc: T): Params<T> = ParamsImpl(doc) inline fun <reified T> doSomething(init: Params<T>.() -> Unit) { val doc = T::class.java.newInstance() val params = createImpl(doc) params.init() } 

此方法不必内联(因为您只是将一个通用实例传递给它,而您已经在doSomething方法中创建了该实例),因此可以在其私有实现中使用ParamsImpl

它的返回类型是Params<T>也是很重要的,所以它只会把这个类型暴露给doSomething的用户。


编辑:

要隐藏创建方法,您可以将@PublishedApi注释与internal可见性结合使用:

 @PublishedApi internal fun <T> createImpl(doc: T): Params<T> = ParamsImpl(doc) 

这将使其inline函数中的使用,但隐藏其他用户。

这意味着在其他模块中,它将不会在Kotlin代码中可见,并且当您尝试从Java调用它时会给您一个错误(当然,这可以被抑制,但这是Kotlin的最佳保证在互操作时可以给你internal可见性)。

你也可以使用构造函数,并用@PublishedApi标记ParamsImpl类本身,如果你更喜欢的话。

这是因为内联函数将内联到调用站点函数中,并且ParamsImpl类的可见性是内部的

你可以很容易地解决这个问题,使doSomething内部可见性。

但是您也可以提取另一个非内联方法来解决问题,例如:

 inline fun <reified T> doSomething(init: Params<T>.() -> Unit) { val doc= T::class.java.newInstance() newParams(doc).init() } fun <T> newParams(doc: T): Params<T> { return ParamsImpl<T>(doc) } 

如果您不想将ParamsImpl公开给其他人,则必须使用反射 ,例如:

 inline fun <reified T> doSomething(init: Params<T>.() -> Unit) { val doc = T::class.java.newInstance() // v--- the full qualifier class name Class.forName("pkg.ParamsImpl").getDeclaredConstructor(Any::class.java).run { isAccessible = true @Suppress("UNCHECKED_CAST") (newInstance(doc) as Params<T>).init() } }