zoukankan      html  css  js  c++  java
  • Kotlin 之操作符重载

    Kotlin 之操作符重载

     

    参考:

    1. kotlin in action
    2. kotlin 官方参考文档

    运算符重载

    Kotlin允许我们为自己的类型提供预定义的一组操作符实现(这些操作符都对应的成员函数或扩展函数),他们是一一对应的,如:
    (+ 对应 plus);

    通过这个操作符,如+,可调用plus 方法;
    如:在Kotlin中,为类定义了一个plus方法,按照约定,可以在该类型实例上通过+运算符,来实现 调用 plus方法;

    重载操作符的函数需要用 operator关键字标记;

    从以下类开始

    data class Pointer(val x:Int, val y:Int)
    

    1. 重载算术运算符

    在Kotlin中,使用约定最直接的就是算术运算符了;对比java
    ,java只能用在基本类型中;

    1.1 重载二元运算符

    用于操作符重载的所有函数使用 operator关键字标记,这里不是碰巧的;

    a. 重载成员函数

    Pointer类添加 + 号操作,把2个点的x,y加在一起

    ```
    operator fun plus(other:Pointer) :Pointer {
        return Pointer(x + other.x, y + other.y)
    }
    ```
    

    b. 重载扩展函数

    这就厉害了,可给第三方库的一些类,实现重载操作符了;

    重要说明

    Kotlin限定了只能重载哪些操作符,以及在类中定义的名字,这样就避免了操作符的滥用;

    可重载的二元算术运算符

    ```
    表达式     函数  
    a*b         times
    a/b         div
    a%b         mod
    a+b         plus
    a-b         minus
    ```
    

    c. 优先级的概念

    与标准数字类型的运算符有着相同的优先级;

    d.其他说明

    定义运算符时,2个运算数,可以是不同的类型,比如如下:

    ```
    operator fun div(scale:Float):Pointer {
            return Pointer((x * scale).toInt(), (y * scale).toInt())
    }
    ```
    

    Kotlin运算符不支持交换性(比如:乘法的交换律)

    比如:1.5 * pointer 与 pointer * 1.5是不一样的;

    同于运算数,运算符函数的返回类型也可以不一样,如:

    ```
    operator fun Char.times(count:Int):String {
        return toString().repeat(count)
    }
    ```
    

    同于普通函数,operator方法允许重载(形参参数类型不一样);

    1.2 位运算

    Kotlin中,没有为标准数字类型,定义任何位运算符;他们使用中缀调用语法的常规函数;

    比如:xor,and,or 等;

    1.3 重载复合赋值运算符

    +=, -=这种被称为复合赋值运算符,kotlin也是支持的;

    在一些情况下,定义+= 运算可以修改变量所引用的对象,但不会重新分配引用,用于可变集合;

    ```
    val nums = ArrayList<Int>()
        nums += 58      // 类似调用add方法
        println(nums)
    ```
    

    Kotlin为标准可变集合定义plusAssign函数(minusAssign,timesAssign)等,可以看下其源代码;

    1.4 重载一元运算符

    -a, +a 这种一元运算符,与上面的类似,函数名不能随意取

    可重载的一元算术运算符

    ```
    表达式     函数  
    +a          unaryPlus
    -a          unaryMinus
    !a          not
    ++a,a++     inc
    --a,a--     dec
    ```
    

    例子:

    ```
    operator fun unaryMinus() = Pointer(-x, -y)
    
    // inc dec 编译器支持 ++a 与 a++
    operator fun BigDecimal.inc() = this + BigDecimal.ONE
    
    fun main(args: Array<String>) {
        var n = BigDecimal.ZERO
        println(n++)        // 0
        println(++n)        // 2
    }
    ```
    

    2. 重载比较运算符

    类似于算术运算符,在Kotlin中,可以对任何对象使用比较运算符(==、!=、 >、<)等,可以不用像Java那种调用equals,compareTo函数;

    2.1 等号运算符 ==

    Kotlin的约定原则之一是:使用==会转换成equals方法调用;但== 与 !=更安全,会自动检测是否为 null,如果不为null,才进行判断;

    即:a == b ===> a?.equals(b) ?: (b==null)

    例子

    ```
    val p = Pointer(1, 2)
    val p2 = Pointer(1, 2)
    println(p == p2)
    ```
    

    equals不需要 operator,因为在Any里面标记过了;

    2.2 恒等运算符 ===

    恒等运算符等价于Java中的 == 运算符:检查2个参数的是否是同一个对象的引用(基本类型判断值是否相同)

    === 不能被重载

    2.3 排序运算符 compareTo

    Java中,如果对象需要比较,得使用Comparable接口,不支持 > <这种,

    Kotlin中,可以使用> < 这种符号了, (<,>, <= ,>=) 会转换成 compareTo 约定调用;

    即:a >= b =====> a.compareTo(b) >= 0

    例子

    ```
    class Person(val firstName: String, val lastName: String) : Comparable<Person> {
        override fun compareTo(other: Person): Int {
            // 先姓,再名
            return compareValuesBy(this, other, Person::lastName,
                    Person::firstName)
        }
    }
    ```
    

    在Kotlin中,可以直接使用java中实现Comparable接口的类,采用更加简洁的运算符语法;

    如:println("abc" < "bac")

    3. 集合与区间的约定

    处理集合最常见的一些操作,是通过下标来获取和设置元素,还有就是检查了;

    这些kotlin中也是支持运算符操作的;

    获取 a[1](下标操作符),可使用in运算符来检查元素是否在集合或区间内;

    3.1 通过下标来访问元素:[] get与set

    下标运算符是一个约定,会转换成对应的 get 或 set方法的调用,比如:map

    例子

    get方法并用 operator标记;

    ```
    operator fun Pointer.get(i: Int): Int {
        return when (i) {
            0 -> x
            1 -> y
            else -> throw IndexOutOfBoundsException("Invalid params: $i")
        }
    }
    ```
    

    这个get方法,参数可以是任意类型,比如:map;也可以定义具有多个参数的get方法;

    例子

    ```
    operator fun MutablePointer.set(index: Int, value: Int) {
        when (index) {
            0 -> x = value
            1 -> y = value
            else -> throw IndexOutOfBoundsException("Invalid params: $index")
        }
    }
    
    ```
    

    3.2 in 的约定

    用于检测某个对象,是否符合某个集合,对应的函数是:
    contains

    例子

    ```
    data class Rectangle(val left: Pointer, val right: Pointer)
    
    operator fun Rectangle.contains(p: Pointer): Boolean {
        return p.x in left.x until right.x &&
                p.y in left.y until right.y
    }
    
    fun main(args: Array<String>) {
        val rect = Rectangle(Pointer(10, 20), Pointer(50, 50))
        println(Pointer(20, 48) in rect)
    }
    ```
    

    in 右边的对象将会调用 contains函数,in 左边的对象,作为入参;

    3.3 rangeTo 的约定

    (0..10)创建一个闭区间,表示0到10的所有数字,共11个,
    实际这里的..调用的是rangeTo函数;

    方法签名(Kotlin标准库中)为,我没找到:

    3.4 for循环的in

    for 循环中的in是用来执行迭代 iterator,这是一种约定;
    也就是说 iterator函数,可使用 in 运算符,来实现迭代;

    定义在哪里的,还是没找到;

    2018-02-06 补充,找到了,其实也是一种约定(来自androidx.view.ViewGroup);

    operator fun ViewGroup.iterator() = object : MutableIterator<View> {
        private var index = 0
        override fun hasNext() = index < childCount
        override fun next() = getChildAt(index++) ?: throw IndexOutOfBoundsException()
        override fun remove() = removeViewAt(--index)
    }
    

    4.方法调用补充

    调用操作符

    ```
    表达式     翻译为
    a()         a.invoke()
    a(i)        a.invoke(i)
    a(i,j)      a.invoke(i,j)
    
    ```
  • 相关阅读:
    ORACLE触发器简单列子
    接口测试中需要携带token的接口返回结果偶尔报无权限
    接口自动化测试用例偶尔报无权限的解决办法
    python中的faker库生成数据,并写入txt文本中
    anaconda在sys.path删除~/.local/lib
    题解12/12 模拟赛
    题解BalticOI 2020
    题解12/09 模拟赛
    亿些原古博客汇总
    bijective proof problems 选做
  • 原文地址:https://www.cnblogs.com/it-tsz/p/11632459.html
Copyright © 2011-2022 走看看