Warning: file_get_contents(/data/phpspider/zhask/data//catemap/4/kotlin/3.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Kotlin 如何将扩展转换为成员?_Kotlin - Fatal编程技术网

Kotlin 如何将扩展转换为成员?

Kotlin 如何将扩展转换为成员?,kotlin,Kotlin,Kotlin允许您扩展泛型类的具体实例。例如,假设我有以下类Foo,带有扩展函数Foo.bar()和Foo.bar(): Foo类(t:t){ val a:String=“bar” val b:Int=111 } fun Foo.bar()=a fun Foo.bar()=b 趣味主线(args:Array){ val stringBar:String=Foo(1).bar() val intBar:Int=Foo(“”.bar() } 在没有扩展函数的情况下是否可以实现此行为?如果可以,如何

Kotlin允许您扩展泛型类的具体实例。例如,假设我有以下类
Foo
,带有扩展函数
Foo.bar()
Foo.bar()

Foo类(t:t){
val a:String=“bar”
val b:Int=111
}
fun Foo.bar()=a
fun Foo.bar()=b
趣味主线(args:Array){
val stringBar:String=Foo(1).bar()
val intBar:Int=Foo(“”.bar()
}

在没有扩展函数的情况下是否可以实现此行为?如果可以,如何将扩展函数转换为成员?是否可以不重命名或更改类型签名?

您可以使用具体化的通用参数创建内联成员函数:

class Foo<T>(t: T) {
    val a: String = "bar"
    val b: Int = 111

    inline fun <reified T, E> member(): E? {
        var r: E? = null
        when(T::class) {
            String::class -> r = b as E
            Int::class -> r = a as E
        }
        return r
    }
}

fun main(args: Array<String>) {
   val str = Foo(1).member<Int, String>()
   val i = Foo("").member<String, Int>()
}
Foo类(t:t){
val a:String=“bar”
val b:Int=111
内联乐趣成员():E{
变量r:E?=null
when(T::class){
字符串::类->r=b作为E
Int::class->r=a作为E
}
返回r
}
}
趣味主线(args:Array){
val str=Foo(1).member()
val i=Foo(“”.member()
}

但是扩展函数在您的情况下更好:它们是类型安全的,更简洁易读。

不,这是不可能的(当前接受的答案与您的代码完全不同)

使用反射,您不必自己进行类型和属性之间的映射

成员函数
propertyValue()
将返回第一个属性的值,该属性的类型为泛型参数或
null

class Foo {
    val a: String = "bar"
    val b: Int = 111

    inline fun <reified T> propertyValue() = Foo::class.memberProperties.firstOrNull {
        it.returnType == T::class.createType()
    }?.get(this)
}

Foo().propertyValue<Int>()) // 111
Foo().propertyValue<String>()) // bar
Foo().propertyValue<Double>()) // null
class-Foo{
val a:String=“bar”
val b:Int=111
inline fun propertyValue()=Foo::class.memberProperties.firstOrNull{
it.returnType==T::class.createType()
}?得到(这个)
}
Foo().propertyValue())/111
Foo().propertyValue())//bar
Foo().propertyValue())//null

当然,您可以扩展此函数,这样它将为您提供所需类型的所有属性值
T
(例如,如果您有多个
Int
属性)。

您的代码还允许调用,例如
Foo(1.0).member()
这是不可取的。第一个泛型参数意味着当返回结果的第二类类型为expression时在
中签入的类类型。如果我们将
File
指定为第二个泛型类型,则应在函数中处理它,否则将引发异常。“意欲如此”,但无法强制执行或检查此操作。例如,您需要从val x=Foo(1)开始,然后修改为1.0,您需要记住也要修改所有方法调用。在您没有的原始代码中,编译器会告诉您。这里的第二个参数没有返回任何参数(IMO)有用。那么Kotlin如何实现扩展以能够基于泛型类型(通常会被删除)进行分派,以及Kotlin如何使泛型数据类型上的扩展可供Java使用者使用,也就是说,是什么使扩展在这里特别?比如正常重载,方法是在编译时选择的,在删除任何内容之前。对于Java使用者来说,扩展只是将接收者作为参数的方法。由于JVM的限制,在这种情况下,它们将有不同的名称。由于擦除后返回类型不同,JVM允许这种重载。我不记得Java本身是否允许它。是的,JVM允许两个函数,它们在同一范围内只在返回类型上不同,但Java不允许。请看这个线程:我的意思是擦除前不同的参数类型和擦除后不同的返回类型的组合。不允许仅在返回类型上重载的正常原因不适用。但是,是的,Java不允许它(),而Kotlin允许它,无论是对于扩展方法还是不允许它。
class Foo {
    val a: String = "bar"
    val b: Int = 111

    inline fun <reified T> propertyValue() = Foo::class.memberProperties.firstOrNull {
        it.returnType == T::class.createType()
    }?.get(this)
}

Foo().propertyValue<Int>()) // 111
Foo().propertyValue<String>()) // bar
Foo().propertyValue<Double>()) // null