以下是简短的答案:
fun Int.makeHexString(): String = toString(radix = 16)
println(255.makeHexString())) // ✅ correct
val f = Int::makeHexString
println(255.f())) // ❌ compiler error!
为了进行更详细的说明,让我们从一个普通(非扩展)函数开始.假设我们有一个转换,它接受一个数字并返回String
.
fun makeHexString(n: Int): String = n.toString(radix = 16)
println(makeHexString(255)) // ff
在Kotlin中,我们可以创建一个变量,该变量包含对此函数的引用.可以以与原始函数相同的方式调用该引用.
fun makeHexString(n: Int): String = n.toString(radix = 16)
val f = ::makeHexString
println(f(255)) // ff
变量f
有一个类型,这是它所指向的函数的类型.在本例中,函数的类型为(Int) -> String
,因为它接受类型为Int
的参数并返回String
.编译器已经自动推断出这个类型,因为我们没有指定它.
如果我们愿意,我们可以将原始函数重写为扩展函数.
fun Int.makeHexString(): String = toString(radix = 16)
val hex = 255.makeHexString()
行为是相同的,但我们现在调用函数的方式不同了.输入数字显示在接收器位置,而不是参数列表中.
如果我们使用稍微不同的语法,我们仍然可以引用扩展函数.
fun Int.makeHexString(): String = toString(radix = 16)
val f = Int::makeHexString
println(255.f())) // ❌ compiler error!
但请注意,我们can't调用引用的方式与调用原始函数的方式相同.上面的代码不能编译.
原因是Kotlin假设该函数的类型实际上仍然是(Int) -> String
.这就是你在问题中引用的文件中描述的内容.
我们可以通过为函数指定显式类型来修复它.我们可以指定Int.() -> String
而不是(Int) -> String
,以指示输入应该在接收器位置,而不是在参数列表中.
fun Int.makeHexString(): String = toString(radix = 16)
val f: Int.() -> String = Int::makeHexString
println(255.f())
现在,我们可以调用函数引用作为扩展,就像我们可以调用原始函数一样.
Select 将一个函数转换为扩展函数是一种风格和人体工程学的 Select ,可以使该函数更易于实现或调用.但是,在使用lambdas和高阶函数时,能够将函数视为多态和可互换的函数通常很有用.接收器和参数之间的区别在这里只是表面上的,所以Kotlin Select 忽略它,除非您明确地说明.