访问通用功能中的对象属性

时间:2018-11-21 12:40:32

标签: generics kotlin

如何在通用函数中访问对象属性?代码,我目前对error: unresolved reference: name提出过要求。我该如何运作? 有where个关键字,但我没有找到太多有关它的信息。

fun <T> foo(t:T): String{
    return t.name
}

foo(object {
    val name = "Foo"
})

相当于C ++:

struct {
    int name{10};
}a;

template<typename T>
int foo(T&t) {
    return t.name;
}

foo(a);

4 个答案:

答案 0 :(得分:1)

以下是使用反射在Kotlin中进行操作的示例(注意:此处您甚至不需要使用该函数的泛型信息):

fun foo(t : Any) = with(t::class.java.getDeclaredField("name")) {
  isAccessible = true
  get(t) as String
}

with并不是必需的。您当然可以完全不同。只是想展示一下在Kotlin中的样子。

我在评论中说了一种reified类型,但实际上您在这里不需要。

要解决问题的最大问题是,您有一个匿名类型,该类型基本上将可能的解决方案缩小为“使用反射”;-)

如果您具有如下类型/接口:

interface Nameable {
  val name : String
}

然后您可以将foo方法更改为:

fun foo(t : Nameable) = t.name

并调用它会导致:

foo(object : Nameable {
  override val name = "Foo"
}

但是,它仍然不是C ++模板,如果想要完全动态,并且必须在创建匿名类型等时使用它们,则必须创建许多适当的接口。 >

答案 1 :(得分:0)

如果要访问某些特定类型的成员,则应在类型参数上应用上限。 可以这样实现:

fun <T : MyTypeThatHasNameProperty> foo(t: T): String{
    return t.name
}

答案 2 :(得分:0)

不能。 T可以是运行时任何类型的实例。因此您无法访问该属性。

尽管如此,您可以做类似的事情

fun <T : SomeType> foo(t: T): String {
    return t.name
}

open class SomeType(val name: String)

foo(SomeType("value"))

编辑: 如果您真的想使用non-named object来实现这一点,那么我可以想到这样的事情。

fun <T : BaseType> foo(t: T): String {
    return t.name
}

interface BaseType {
   val name: String
}

foo(object :BaseType {
        override val name = "value"
})

答案 3 :(得分:0)

有可能在泛型中使用Kotlin reified type parameters

foo(object {
    val name = "Foo"
})


inline fun <reified T> foo(t: T): String =
    T::class.declaredMembers.find { it.name == "name" }!!
    .call(t) as String

第二种选择是直接从::class获得t

fun <T: Any> foo(t: T): String =
    t::class.declaredMembers.find { it.name == "name" }!!.call(t) as String

第三个选择是为您提供通用参数上限:

foo( NameProvider {
    val name = "Foo"
})

interface NameProvider {
    val name: String
}

fun <T: NameProvider> foo(t: T): String = t.name