【问题标题】:Kotlin extension functions - Difference between Any? and Generic T?Kotlin 扩展函数 - Any 之间的区别?和通用 T?
【发布时间】:2019-01-09 15:44:55
【问题描述】:

我正在做一些有趣的编码,我想知道我应该使用哪一个。两者都试过了,他们给了我同样的结果。那么,这两者有什么区别呢?

例子:

fun Any?.foo() = this != null

fun <T> T?.foo() = this != null

实际的函数有点复杂,它实际上是根据对象的真实类型做一些事情(比如带有一些选项的when

【问题讨论】:

标签: kotlin


【解决方案1】:

第二个函数为您提供了一个在这种特殊情况下未使用的机会:它将接收器的类型捕获到类型参数T 中,以便您可以在其他地方使用它签名,例如在参数类型或返回值类型中,或在函数体中。

作为一个非常综合的示例,第二个函数中的listOf(this, this) 将被键入为List&lt;T?&gt;,保留项目类型与接收者类型相同的知识,而第一个函数中的相同表达式将是List&lt;Any?&gt;

第一个函数不允许您一般使用接收器类型来存储该类型的项目,接受与参数相同类型的附加项目或在函数的返回值类型中使用接收器类型,而第二个函数允许所有这些。

这些函数从运行时的角度来看是等价的,就像编译代码时的generics are erased from the JVM bytecode一样,所以你将无法在运行时确定类型T并根据它进行操作,除非你将函数转换为一个inline function with a reified type parameter


作为一个非常重要的特殊情况,将调用站点中的类型捕获到类型参数中允许高阶函数接受另一个在其签名中使用T 的函数。标准库有一组作用域函数(runapplyletalso),它们显示了差异。

假设also 的签名没有使用泛型,看起来像这样:

fun Any?.also(block: (Any?) -> Unit): Any? { ... }

这个函数可以在任何对象上调用,但它的签名并没有表明它是传递给block并从函数返回的接收器对象——编译器将无法确保类型安全和,例如,允许在没有类型检查的情况下调用接收者对象的成员:

val s: String = "abc"

// won't compile: `it` is typed as `Any?`, the returned value is `Any?`, too
val ss1: String = (s + s).also { println(it.length) } 

// this will work, but it's too noisy
val ss2: String = (s + s).also { println((it as String).length) } as String 

现在,捕获类型参数正是表明它在所有三个地方都是相同类型的方式。我们修改签名如下:

fun <T : Any?> T.also(block: (T) -> Unit): T { ... }

编译器现在可以推断类型,知道它在任何地方出现的T都是相同的类型:

val s: String = "abc"

// OK!
val ss: String = (s + s).also { println(it.length) } 

【讨论】:

  • 这个例子帮助我掌握了这个概念。总结一下:Any 泛型保留了Any 类型,而T 允许根据分配的值更改类型。
【解决方案2】:

如果你在 JVM 上运行它,你会得到以下结果

java.lang.ClassFormatError:类中的方法名称和签名重复 文件...

这很有趣,所以从签名的角度来看,它们是相同的。

这在很大程度上取决于您的用例,但在大多数情况下,您可能希望使用泛型变体,因为类型可能是可变的,但在编译时是固定的。这个优势在这里变得很明显:

fun Any?.foo() = this
fun <T> T?.bar() = this

fun main(args: Array<String>) {
    val x = 5.foo() // Any?
    val y = 5.bar() // Int?
}

Int? 上可用的所有属性和函数将不能用于 x,直到我明确地将其强制转换(到和 Int?)。另一方面,y“知道”它返回了 Int?


在您的示例中,这不会有什么不同,因为您将始终返回 Boolean,并且如已经显示的那样,签名是相同的。

【讨论】:

    猜你喜欢
    • 2020-12-09
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-05-19
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多