Kotlin 双冒号的作用

1,516 阅读2分钟

介绍

kotlin中有一个神秘的符号“::”,双冒号,我们在项目中常见也经常使用的地方就是ClassA::class,这里我们获取到了ClassA的引用,那么双冒号的作用是不是就是获取类的引用呢?是,但不仅仅是。

引用的分类

类引用

开头所说的例子就是通过::class获取类的引用

val c = MyClass::class

而要实现java类引用的效果,则需要添加.java成为::class.java。

val c = MyClass::class.java

属性引用

类的属性作为对象来使用,可以使用::操作符



var x = 1



fun main() {

    ::x.set(2)

    print(x)

}

访问类的成员属性时,可以使用类名+双冒号+属性的方式进行限定,将属性引用存储在显式指定类型的变量中



class KtTest(val age: Int) 



fun main() {

    val temNum = KtTest::age

 print(temNum.get(KtTest(3)))

}

函数引用

普通函数引用

fun isOdd(x: Int) = x % 2 != 0

对于这个函数,可以直接使用 isOdd(5) 进行调用,但是当这个方法作为参数时,就可以使用函数引用来调用



fun isOdd(x: Int) = x % 2 != 0



fun test() {

    val numbers = listOf(1, 2, 3)

    numbers.filter(::isOdd)

}

看源码,filter操作符接收的是一个lambda参数



public inline fun <T> Iterable<T>.filter(predicate: (T) -> Boolean): List<T> {

    return filterTo(ArrayList<T>(), predicate)

}

众所周知,kotlin里的方法等价于一个lambda,所以可以把isOdd方法作为参数传递进去,但是要注意条件:只有方法的参数与返回值和lambda一样,才可以作为参数传递。

构造函数引用

当需要的函数类型与构造函数的参数类型、返回值一样时,构造函数也可以以引用方式调用。



fun showName(num: Int): Boolean = num % 2 == 0

class KtTest {

    fun main() {

        getKtTest(::KtTest)

    }

}



fun getKtTest(kt: () -> KtTest){

    val ktTest = kt()

}

顶层函数引用

顶层函数也可以作为参数被使用。

fun showName(num: Int): Boolean = num % 2 == 0

class KtTest {

    fun main() {

        val data = listOf(1, 2, 4)

        data.filter(::showName)

    }

}

拓展函数引用

同样的,拓展函数也可以通过引用调用

fun String.hasNumber(): Boolean {

    var hasNumber = false

    this.forEach {

 hasNumber = it >= '0' || it <= '9'

    }

 return hasNumber

}





val str = "AB2C"

val hasNumbers = str::hasNumber

引用绑定

方法引用绑定

kotlin允许使用特定的引用语法获取实例对象上的方法引用,格式为:对象实例 :: 成员

fun main() {

    val numberRegex = "\d+".toRegex()

    println(numberRegex.matches("26"))



    //存储numberRegex的引用,这时numberRegex的引用被绑定到了接收者numberRegex上

    val isNumber = numberRegex::matches

    println(isNumber("26"))

}

我们不是直接调用matches()方法,而是存取对它的引用,这样的引用会被绑定到其接收者身上,它可以直接调用(如上例所示),或者用于任何期待一个函数类型表达式的时候

fun main() {

    val numberRegex = "\d+".toRegex()

    val strings = listOf("abc", "124", "a70")

    println(strings.filter(numberRegex::matches))

}

比较绑定的类型和相应的未绑定类型的引用(即上面的两种使用方式), 绑定的可调用引用有其接收者“附加”到其上,因此接收者的类型不再是参数:

\已绑定

val isNumber: (CharSequence) -> Boolean = numberRegex::matches



\未绑定

val matches: (Regex, CharSequence) -> Boolean = Regex::matches

属性引用绑定

fun main() {

    val prop = "abc"::length

    println(prop.get())

}

无需显式指定 this 作为接收者:this::foo::foo 是等价的。

构造函数引用的绑定

class Outer {

    inner class Inner

}



val o = Outer()

val boundInnerCtor = o::Inner

内部类构造函数绑定的可调用引用可通过提供外部类的实例来获得

参考

【1】book.kotlincn.net/text/reflec…