改进的类型参数和内部

时间:2017-07-25 07:52:05

标签: generics kotlin inline

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

我基本上想要的是:

/* 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()
}

2 个答案:

答案 0 :(得分:3)

您可以通过添加中间方法来创建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可见性的最佳保证。

如果您愿意,也可以使用构造函数并使用ParamsImpl@PublishedApi类标记为自己。

答案 1 :(得分:0)

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

您可以通过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)
}

IF 您不希望向其他人公开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()
    }
}