Kotlin 泛型内联函数

Kotlin 泛型内联函数,kotlin,Kotlin,假设我有一个对象可以帮助我从存储中反序列化其他对象: val books: MutableList<Book> = deserializer.getBookList() val persons: MutableList<Person> = deserializer.getPersonList() 是否有一些Kotlin magic(可能带有内联函数)可用于检测列表类型并泛化此方法?我认为问题是val item=T()这对泛型类型不起作用,对吗?或者内联函数可以这样做吗?

假设我有一个对象可以帮助我从存储中反序列化其他对象:

val books: MutableList<Book> = deserializer.getBookList()
val persons: MutableList<Person> = deserializer.getPersonList()

是否有一些Kotlin magic(可能带有内联函数)可用于检测
列表
类型并泛化此方法?我认为问题是
val item=T()
这对泛型类型不起作用,对吗?或者内联函数可以这样做吗?

您不能调用泛型类型的构造函数,因为编译器不能保证它有一个构造函数(类型可能来自接口)。不过,您可以做的是将“creator”函数作为参数传递给您的函数。像这样:

fun <T> DataInput.getList(createT: () -> T): MutableList<T> {
    val list = mutableListOf<T>()
    val size = this.readInt()

    for(i in 0 .. size) {
        val item = createT()
        /* Unless readExternal is an extension on Any, this function 
         * either needs to be passed as a parameter as well,
         * or you need add an upper bound to your type parameter
         * with <T : SomeInterfaceWithReadExternal>
         */
        item.readExternal(this)
        list.add(item)
    }

    return list
}
fun DataInput.getList(createT:()->T):可变列表{
val list=mutableListOf()
val size=this.readInt()
用于(0.尺寸中的i){
val item=createT()
/*除非readExternal是任何函数的扩展,否则此函数
*两者都需要作为参数传递,
*或者需要向类型参数添加上限
*与
*/
item.readExternal(本)
列表。添加(项目)
}
返回列表
}
现在您可以这样调用函数:

fun DataInput.getBookList(): MutableList<Book> {
    val list = mutableListOf<Book>()
    val size = this.readInt()

    for(i in 0 .. size) {
        val item = Book()
        item.readExternal(this)
        list.add(item)
    }

    return list
}
val books: MutableList<Book> = deserializer.getList(::Book)
val persons: MutableList<Person> = deserializer.getList(::Person)
valbooks:MutableList=反序列化程序.getList(::Book)
val persons:MutableList=反序列化程序.getList(::Person)

您不能调用泛型类型的构造函数,因为编译器不能保证它有构造函数(类型可能来自接口)。不过,您可以做的是将“creator”函数作为参数传递给您的函数。像这样:

fun <T> DataInput.getList(createT: () -> T): MutableList<T> {
    val list = mutableListOf<T>()
    val size = this.readInt()

    for(i in 0 .. size) {
        val item = createT()
        /* Unless readExternal is an extension on Any, this function 
         * either needs to be passed as a parameter as well,
         * or you need add an upper bound to your type parameter
         * with <T : SomeInterfaceWithReadExternal>
         */
        item.readExternal(this)
        list.add(item)
    }

    return list
}
fun DataInput.getList(createT:()->T):可变列表{
val list=mutableListOf()
val size=this.readInt()
用于(0.尺寸中的i){
val item=createT()
/*除非readExternal是任何函数的扩展,否则此函数
*两者都需要作为参数传递,
*或者需要向类型参数添加上限
*与
*/
item.readExternal(本)
列表。添加(项目)
}
返回列表
}
现在您可以这样调用函数:

fun DataInput.getBookList(): MutableList<Book> {
    val list = mutableListOf<Book>()
    val size = this.readInt()

    for(i in 0 .. size) {
        val item = Book()
        item.readExternal(this)
        list.add(item)
    }

    return list
}
val books: MutableList<Book> = deserializer.getList(::Book)
val persons: MutableList<Person> = deserializer.getList(::Person)
valbooks:MutableList=反序列化程序.getList(::Book)
val persons:MutableList=反序列化程序.getList(::Person)
注意: 正如marstran在一篇评论中提到的,这需要类有一个零参数构造函数才能工作,否则它将在运行时抛出异常。如果构造函数不存在,编译器不会警告您,因此如果您选择这种方式,请确保您实际传递了一个具有零参数构造函数的类


不能在Kotlin或Java中初始化泛型类型。至少不是以“传统”的方式。你不能这样做:

val item = T()
在Java中,您需要传递一个
,然后获得构造函数。这是一个非常基本的例子:

public <T> void x(Class<T> cls){
    cls.getConstructor().newInstance(); // Obviously you'd do something with the return value, but this is just a dummy example
}
但是,
readExternal
Any
中不存在,这将带来问题。唯一的例外是,如果您有一个扩展函数用于
Any
或具有该名称和输入的泛型类型

如果它是特定于某些类的,那么您不能这样做,除非您有一个共享的父级。例如:

class Book(){
    fun readExternal(input: DataInput) { /*Foo bar */}
}

class Person(){
    fun readExternal(input: DataInput) { /*Foo bar */}
}
这是行不通的。除了
Any
之外,没有共享的父级,
Any
没有
readExternal
。该方法是在每种方法中手动定义的

您可以创建一个共享父级,作为接口或抽象类(假设还没有),并使用
,这样您就可以访问它

当然,您可以使用反射,但它稍微困难一些,并且添加了一些需要处理的异常。我不建议这样做;我个人会使用超类

inline fun <reified T> DataInput.getBookList(): MutableList<T> {
    val list = mutableListOf<T>()
    val size = this.readInt()
    val method = try {
        T::class.java.getMethod("readExternal", DataInput::class.java)
    }catch(e: NoSuchMethodException){
        throw RuntimeException()
    }catch(e: SecurityException){
        throw RuntimeException()// This could be done better; but error handling is up to you, so I'm just making a basic example
        // The catch clauses are pretty self-explanatory; if something happens when trying to get the method itself,
        // These two catch them
    }
    for(i in 0 .. size) {
        val item: T = T::class.java.getConstructor().newInstance()!!
        method.invoke(item, this)
        list.add(item)
    }

    return list
}
inline fun DataInput.getBookList():MutableList{
val list=mutableListOf()
val size=this.readInt()
val方法=尝试{
T::class.java.getMethod(“readExternal”,DataInput::class.java)
}捕获(e:NoSuchMethodException){
抛出RuntimeException()
}捕获(e:SecurityException){
throw RuntimeException()//这可以做得更好;但错误处理取决于您,所以我只做一个基本示例
//catch子句非常不言自明;如果在尝试获取方法本身时发生了什么事情,
//这两个人抓住了他们
}
用于(0.尺寸中的i){
val item:T=T::class.java.getConstructor().newInstance()!!
调用(项,此)
列表。添加(项目)
}
返回列表
}
注意: 正如marstran在一篇评论中提到的,这需要类有一个零参数构造函数才能工作,否则它将在运行时抛出异常。如果构造函数不存在,编译器不会警告您,因此如果您选择这种方式,请确保您实际传递了一个具有零参数构造函数的类


不能在Kotlin或Java中初始化泛型类型。至少不是以“传统”的方式。你不能这样做:

val item = T()
在Java中,您需要传递一个
,然后获得构造函数。这是一个非常基本的例子:

public <T> void x(Class<T> cls){
    cls.getConstructor().newInstance(); // Obviously you'd do something with the return value, but this is just a dummy example
}
但是,
readExternal
Any
中不存在,这将带来问题。唯一的例外是,如果您有一个扩展函数用于
Any
或具有该名称和输入的泛型类型

如果它是特定于某些类的,那么您不能这样做,除非您有一个共享的父级。例如:

class Book(){
    fun readExternal(input: DataInput) { /*Foo bar */}
}

class Person(){
    fun readExternal(input: DataInput) { /*Foo bar */}
}
这是行不通的。除了
Any
之外,没有共享的父级,
Any
没有
readExternal
。该方法是在每种方法中手动定义的

您可以创建一个共享父级,作为接口或抽象类(假设还没有),并使用
,这样您就可以访问它

当然,您可以使用反射,但它稍微困难一些,并且添加了一些需要处理的异常。我不建议这样做;我个人会使用超类

inline fun <reified T> DataInput.getBookList(): MutableList<T> {
    val list = mutableListOf<T>()
    val size = this.readInt()
    val method = try {
        T::class.java.getMethod("readExternal", DataInput::class.java)
    }catch(e: NoSuchMethodException){
        throw RuntimeException()
    }catch(e: SecurityException){
        throw RuntimeException()// This could be done better; but error handling is up to you, so I'm just making a basic example
        // The catch clauses are pretty self-explanatory; if something happens when trying to get the method itself,
        // These two catch them
    }
    for(i in 0 .. size) {
        val item: T = T::class.java.getConstructor().newInstance()!!
        method.invoke(item, this)
        list.add(item)
    }

    return list
}
inline fun DataInput.getBookList():Mut