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. 解构约定

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

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

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

    public final operator fun component1(): Float{ return x }

    public final operator fun component2(): Float{ return y }

或者

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

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

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

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

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

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

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

data class Result(val errorCode: Int, val message: Int,val result:String)

fun getHttpResponse(): Result { 
    return Result(resultCode, status,josnBody)
}

------------------------------------------------------------------
//获取返回值
val(errorCode, message, result) = getHttpResponse()
  • 在 lambda 表达式中解构

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

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

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

4.invoke约定

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

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

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

下面的代码:

class TestInvoke() {

    operator fun invoke() {
        println("invoke()")
    }

    operator fun invoke(value: Int) {
        println("invoke value")

    }

    operator fun invoke(func: ()->Unit) {
        func()
    }
}

val test = TestInvoke()
        test()
        test(1)
        test{
            println("似乎比较有用的")
        }

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

@SinceKotlin("1.3")
interface FunctionN<out R> : Function<R>, FunctionBase<R> {
    /**
     * Invokes the function with the specified arguments.
     *
     * Must **throw exception** if the length of passed [args] is not equal to the parameter count returned by [arity].
     *
     * @param args arguments to the function
     */
    operator fun invoke(vararg args: Any?): R

    /**
     * Returns the number of arguments that must be passed to this function.
     */
    override val arity: Int
}

5. Iterator约定

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

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

以上就是kotlin的约定。

引用:

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

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值