具体化的类型参数和内部结构
Reified type parameters and internals
我有一个通用函数,它需要实例化其通用参数的对象并将其传递给某个接口的实例。
据我所知,实例化该通用对象的唯一方法是使函数内联并具体化该类型参数。但我不想公开该接口的实现。
问题是内联函数不能使用 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()
}
您可以通过添加中间方法来创建您的 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
在其私有实现中。
它的 return 类型是 Params<T>
也很重要,这样它只会将该类型公开给 doSomething
.
的用户
编辑:
要隐藏创建方法,可以使用@PublishedApi
注解结合internal
可见性:
@PublishedApi internal fun <T> createImpl(doc: T): Params<T> = ParamsImpl(doc)
这将允许它在 inline
函数中使用,但对其他用户隐藏。
这意味着在其他模块中,它不会在 Kotlin 代码中可见,并且当您尝试从 Java 调用它时它会给您一个错误(当然,这可以被抑制, 但这是 Kotlin 在进行互操作时可以给你的 internal
可见性的最好保证。
您也可以使用构造函数并将 ParamsImpl
class 本身标记为 @PublishedApi
,如果您更喜欢那样的话。
这是因为内联函数将被内联到调用点函数中,并且 ParamsImpl
class 的可见性是 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)
}
如果你不想暴露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()
}
}
我有一个通用函数,它需要实例化其通用参数的对象并将其传递给某个接口的实例。
据我所知,实例化该通用对象的唯一方法是使函数内联并具体化该类型参数。但我不想公开该接口的实现。
问题是内联函数不能使用 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()
}
您可以通过添加中间方法来创建您的 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
在其私有实现中。
它的 return 类型是 Params<T>
也很重要,这样它只会将该类型公开给 doSomething
.
编辑:
要隐藏创建方法,可以使用@PublishedApi
注解结合internal
可见性:
@PublishedApi internal fun <T> createImpl(doc: T): Params<T> = ParamsImpl(doc)
这将允许它在 inline
函数中使用,但对其他用户隐藏。
这意味着在其他模块中,它不会在 Kotlin 代码中可见,并且当您尝试从 Java 调用它时它会给您一个错误(当然,这可以被抑制, 但这是 Kotlin 在进行互操作时可以给你的 internal
可见性的最好保证。
您也可以使用构造函数并将 ParamsImpl
class 本身标记为 @PublishedApi
,如果您更喜欢那样的话。
这是因为内联函数将被内联到调用点函数中,并且 ParamsImpl
class 的可见性是 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)
}
如果你不想暴露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()
}
}