Generics 具体化类型参数和内部构件

Generics 具体化类型参数和内部构件,generics,kotlin,inline,Generics,Kotlin,Inline,我有一个泛型函数,它需要实例化其泛型参数的对象,并将其传递给某个接口的实例 据我所知,实例化泛型对象的唯一方法是使函数内联并具体化该类型参数。但我不想公开该接口的实现 问题是内联函数不能使用内部类 我基本上想说的是: /* The interface I want to expose */ interface Params<T> { val doc: T } /* The implementation I do not want to expose */ internal

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

我基本上想说的是:

/* 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()
}
/*我要公开的接口*/
接口参数{
val文件:T
}
/*我不想公开的实现*/
内部类ParamsImpl(覆盖val文档:T):Params
/*功能*/
内联乐趣剂量测量(初始:参数。->单位){
val doc=T::class.java.newInstance()
val params=ParamsImpl(doc)//无法编译,因为ParamsImpl是内部的
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()
}
这将启用它在
内联
函数中的使用,但对其他用户隐藏它

这意味着在其他模块中,它在Kotlin代码中不可见,当您尝试从Java调用它时,它会给您一个错误(当然,这可以被抑制,但这是Kotlin在执行互操作时为其
内部
可见性提供的最佳保证)


如果您更喜欢,还可以使用构造函数并用
@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)
}
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()
    }
}

该解决方案的问题是,我必须公开我不想公开的
createImpl
。我只想在内部创建
Params
哇,这真是太棒了
doSomething
需要公开。我不希望使用公共函数来创建
参数
,因为我只希望能够创建它们internally@danielspaniol先生,现在怎么样?看起来很难看。我希望有一个比使用反射更好的解决方案。我不明白为什么不能在
inline
函数中使用
internal
。@danielspaniol您好,这是没有办法的,因为
paraminpl
将内联到调用站点函数中,但是它的可见性是内部的,因此编译器将报告这样的错误。如果您不想公开内部
ParamsImpl
,唯一的方法就是使用反射。我认为既然Kotlins
internal
映射到Javas
public
,编译器就不会有问题
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()
    }
}