• Kotlin 学习笔记(七)operator约定


    约定的意义:就是让函数调用更加简洁。语法糖的一部分吧。

    用一个是更简洁的符号调用,一个是特殊命名的函数。特殊命名是指Kotlin指定了和符号相对于的名字。

     约定的方法都有一个关键字:operator。

    举例:在类中定义了一个名为plus的方法,并且有operator关键字修饰,那么按照约定,你就可以在该类的实例上使用+运算符。

    不知道有没有对你造成困扰。operator不是操作符重载的关键字吗?怎么又变成了什么“约定”的关键字了呢?

    其实kotlin中的约定应用,包含以下几种,都用operator关键字定义。

    1. 操作符号重载约定

    2. 属性委托约定

    3. 解构约定

    4. invoke约定

    5. Iterator约定

    1. 操作符号重载约定

    这个不再细讲了,有一点要注意,不像C++重载时重载函数的名字就是符号,但是kotlin是有映射表的。什么符号对应什么函数名字,比如,“+”对应的是“plus”。另外还有一些特殊一点的重载,比如,[]/get, contains

    2. 属性委托约定

    委托的关键词是by。by右边的对象,必须实现一个委托函数。这个函数用operator修饰。

    委托函数需要返回一个初始化的对象。

    具体详见上一篇:Kotlin学习笔记(八)by的作用,属性委托和类的委托,和Lazy的关系​​​​​​​

    3. 解构约定

    可以把一个对象的属性值,一次性赋值给外面多个变量。

    1. fun test() {
    2. val point = Point(1,2)
    3. val(x,y) = point //此时x=1, y=2
    4. }

    实现上面的效果,需要在Point类实现约定函数:

    1. public final operator fun component1(): Float{ return x }
    2. public final operator fun component2(): Float{ return y }

    或者

    把Point类声明称Data数据类,因为数据类在编译期,除了塞入:

    equals()/hashCode() /toString() , 还会把属性按声明顺序对应一一声明componentN() 。

    同时数据类必须满足以下要求:

    • 主构造函数需要至少有一个参数(可以使用默认参数来实现无参主构造函数)
    • 主构造函数的所有参数需要标记为 val 或 var
    • 数据类不能是抽象、开放、密封或者内部的

    如果说解构就上面举例那个作用,那就太莫名其妙了。一些有意义的作用在于:

    • 遍历map
    1. for ((key, value) in map) {
    2. // 直接使用该 key、value
    3. }
    • 从函数中返回多个变量 

    创建返回信息的数据类,在调用方法获取返回信息。如果使用解构声明将其分成不同的值:

    1. data class Result(val errorCode: Int, val message: Int,val result:String)
    2. fun getHttpResponse(): Result {
    3. return Result(resultCode, status,josnBody)
    4. }
    5. ------------------------------------------------------------------
    6. //获取返回值
    7. val(errorCode, message, result) = getHttpResponse()
    • 在 lambda 表达式中解构

    和map遍历相识,就是将lambda中的Map.Entry参数进行解构声明:

    1. val map = mapOf(1 to 1)
    2. map.mapValues { (key, value) ->
    3. "key = $key ,value = $value "
    4. }

    在lambda中,时常会看到_的使用。就是说这个参数,我现在不需要使用。这其实就是解构中的用法。如果需要时用下划线替代,要不然会得到不想要的属性值。

    4.invoke约定

    如果类使用operator声明了invoke(),则该类的对象就可以当做函数一样调用,即在变量后加上()。就相当于调用指定的方法了。

    如果按照上面定义的意思,似乎也看不出来也有啥有意义的作用。

    体现有意义关键在于,inovke函数可接受的参数类型也包括函数类型。

    下面的代码:

    1. class TestInvoke() {
    2. operator fun invoke() {
    3. println("invoke()")
    4. }
    5. operator fun invoke(value: Int) {
    6. println("invoke value")
    7. }
    8. operator fun invoke(func: ()->Unit) {
    9. func()
    10. }
    11. }
    12. val test = TestInvoke()
    13. test()
    14. test(1)
    15. test{
    16. println("似乎比较有用的")
    17. }

    函数类型其实就是实现了FunctionN接口的匿名类,然后当函数类型是函数类型时,这时传递给它一个lambda,lambda就会被编译成FunctionN的匿名内部类(当然是非内联的),然后调用lambda就变成了一次FunctionN接口的invoke调用。就像上面的例子一样。

    1. @SinceKotlin("1.3")
    2. interface FunctionN<out R> : Function<R>, FunctionBase<R> {
    3. /**
    4. * Invokes the function with the specified arguments.
    5. *
    6. * Must **throw exception** if the length of passed [args] is not equal to the parameter count returned by [arity].
    7. *
    8. * @param args arguments to the function
    9. */
    10. operator fun invoke(vararg args: Any?): R
    11. /**
    12. * Returns the number of arguments that must be passed to this function.
    13. */
    14. override val arity: Int
    15. }

    5. Iterator约定

    for循环中可以使用in运算符来表示执行迭代。这意味着Kotlin的for循环将被转换成list.iterator()的调用,然后反复调用hasNextnext 方法。

    iterator方法也是Kotlin中的一种约定,这意味iterator()可以被定义为扩展函数。例如:Kotlin标准库中为Java的CharSequence定义了一个扩展函数iterator,使我们能遍历一个常规的Java字符串。 

    以上就是kotlin的约定。

    引用:

    Kotlin invoke约定,让Kotlin代码更简洁

  • 相关阅读:
    【数学建模】简单的优化模型-6 血管分支
    nginx manual
    通过 ffmpeg命令行 调节视频播放速度
    从文件下载视角来理解Web API
    Jedis入门及对Redis数据结构的操作
    JDK源码解析-ConcurrentHashMap
    【计算机视觉 | 目标检测】arxiv 计算机视觉关于目标检测的学术速递(9 月 14 日论文合集)
    短信验证码
    计算机网络【UDP与TCP协议(三次握手、四次挥手)】
    离线数仓(四)【数仓数据同步策略】
  • 原文地址:https://blog.csdn.net/zjuter/article/details/126211381