为什么有 'by' 用于扩展 class 并在函数定义中具体化

why there is 'by' for the extended class and reified in function define

遇到一个带有 class 和一个函数的示例,并试图理解那里的 koltin 语法,

  1. 这个IMeta by dataItem有什么作用?查看了 https://kotlinlang.org/docs/reference/classes.html#classes 并且没有看到如何在派生的 class

  2. 中使用 by
  3. 为什么 inline fun <reified T> getDataItem() 中需要 reified?如果有人可以提供示例来解释 reified?

    class DerivedStreamItem(private val dataItem: IMeta, private val dataType: String?) :
        IMeta by dataItem {
    
    override fun getType(): String = dataType ?: dataItem.getType()
    fun getData(): DerivedData? = getDataItem()
    
    private inline fun <reified T> getDataItem(): T? = if (dataItem is T) dataItem else null
    

    }

为了参考,把相关的定义复制到这里:

interface IMeta {
    fun getType() : String
    fun getUUIDId() : String
    fun getDataId(): String?
}

class DerivedData : IMeta {
    override fun getType(): String {
        return ""  // stub
    }

    override fun getUUIDId(): String {
        return ""  // stub
    }

    override fun getDataId(): String? {
        return ""  // stub
    }
}

(既然你问的是两个问题,我就分开回答)

Kolin中的by关键字用于委托。委托有两种:

1) Implementation by Delegation(有时称为Class委派)

这允许您实现接口并将对该接口的调用委托给具体对象。如果您想扩展一个接口但不想实现它的每个部分,这将很有帮助。例如,我们可以通过委托给 List 来扩展它,并允许我们的调用者为我们提供 List

的实现
class ExtendedList(someList: List) : List by someList {
   // Override anything from List that you need
   // All other calls that would resolve to the List interface are 
   // delegated to someList   
}

2) Property Delegation

这允许您做类似的工作,但具有属性。我最喜欢的例子是 lazy,它可以让你懒惰地定义一个 属性。在您引用 属性 之前,不会创建任何内容,并且会缓存结果以便将来更快地访问。

来自 Kotlin 文档:

val lazyValue: String by lazy {
    println("computed!")
    "Hello"
}

why the reified is required in the inline fun <reified T> getDataItem()? If someone could give a sample to explain the reified?

有一些不错的东西documentation on reified type parameters,但我会尽量把它浓缩一下。​​

Kotlin 中的 reified 关键字用于绕过 JVM 对泛型使用类型擦除这一事实。这意味着在运行时,每当您引用泛型类型时,JVM 不会 知道实际类型是什么。这只是编译时的事情。所以 T 在你的例子中......JVM 不知道它是什么意思(没有具体化,我会解释)。

您会注意到在您的示例中您还使用了 inline 关键字。这告诉 Kotlin,与其在引用函数时调用它,不如插入函数体 inline。这在某些情况下可能更有效。所以,如果 Kotlin 已经打算在编译时复制我们函数的主体,为什么不复制 T 代表的 class 呢?这是使用 reified 的地方。这告诉 Kotlin 引用 T 的实际具体类型,并且仅适用于 inline 函数。

如果您要从您的示例中删除 reified 关键字,您会得到一个错误:"Cannot check for instance of erased type: T"。通过具体化这一点,Kotlin 知道实际类型 T 是什么,让我们可以安全地进行这种比较(以及由此产生的智能转换)。