kotlin中的二元运算符重载

作者: o动感超人o | 来源:发表于2018-05-06 23:37 被阅读14次

    可重载的二元算术运算符

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

    在kotlin中,重载运算符需要使用operator修饰符,如

    data class KtOperator(private var num: Int) {
    
        operator fun plus(ktOperator: KtOperator): KtOperator {
            return KtOperator(num + ktOperator.num)
        }
    
    }
    

    在java中调用时,像使用普通函数即可,如

    public static void main(String[] args) {
        KtOperator ktOperator1 = new KtOperator(1);
        KtOperator ktOperator2 = new KtOperator(3);
        System.out.println(ktOperator1.plus(ktOperator2));
    }
    

    当从Kotlin调用Java的时候,对于与Kotlin约定匹配的函数都可以使用运算符语法来调用,由于Java没有定义任何用于标记运算符函数的语法,所以使用operator修饰符的要求对它并不适用,唯一的约束是,参数需要匹配名称和数量,如

    public class JavaOperator {
    
        private int num;
    
        public JavaOperator(int num) {
            this.num = num;
        }
    
        @Override
        public String toString() {
            return "JavaOperator{" +
                    "num=" + num +
                    '}';
        }
    
        public JavaOperator plus(JavaOperator javaOperator) {
            return new JavaOperator(num + javaOperator.num);
        }
    
    }
    

    在kotlin中调用

    fun main(args: Array<String>) {
        val javaOperator1 = JavaOperator(1)
        val javaOperator2 = JavaOperator(1)
        println(javaOperator1 + javaOperator2)
    }
    

    对于+=这样的广义赋值操作符,我总结了一下有这样的问题,当你在代码中用到+=的时候,理论上plus和plusAssign都可能被调用,如果在这种情况下,两个函数都有定义且适用,编译器会报错.

    当遇到+=的时候,系统会这样来判断:

    • 广义赋值操作符的返回值类型必须为 Unit,否则定义的时候系统会提示错误
    • 如果执行 a += b 时 plusAssign 不存在,会尝试生成 a = a + b,其中的 a + b 使用的就是 plus 操作符方法,相当于调用 a = a.plus(b)。并且此时会 要求 a + b 的 plus 方法的返回值类型必须与 a 类型一致(如果单独使用 a + b 不做此要求)。
    • 如果执行 a += b 时 plusAssign 存在,对应的二元算术运算符函数也可用,并且a是var则报错,因为这时候既可以调用 a = a + b,也就是 a = a.plus(b),又可以调用 a.plusAssign(b),它们都符合操作符重载约定,这样就会产生歧义。而如果使用 val 定义 a,则只可能执行 a.plusAssign(b),因为 a 不可被重新赋值,因此 a = a + b 这样的语法是出错的,永远不能被调用,那么调用 a += b 就不会产生歧义了。(plus 对应 plusAssign。minus、times 等也类似。)

    下面给出一个例子:

    fun main(args: Array<String>) {
        val list1 = listOf(1, 2, 3)
        list1 + 1
        list1 += 1//error
    //上面的错误是因为list1是List对象,该对象没有plugAssign方法,所以会尝试生成list1 = list1 + 1,而list1是val的,所以这里报错
    
        var list3 = listOf(1, 2, 3)
        list3 + 1
        list3 += 1//right
    //上面正确是因为list3是List对象,该对象没有plugAssign方法,所以会尝试生成list1 = list1 + 1,而list1是var的,所以这里正确
    
        val list2 = arrayListOf(1, 2, 3)
        list2 + 1
        list2 += 1//right
    //上面正确是因为list2是ArrayList对象,该对象有plugAssign方法,但是因为list2是val的,所以这里只能调用plugAssign方法
    
        var list4 = arrayListOf(1, 2, 3)
        list4 + 1
        list4 += 1//error
    //上面是错误的是因为list4是ArrayList对象,该对象有plugAssign方法,但是因为list2是var的,所以这里调用list4.plus(1)和list4.plusAssign(1)都可以,所以这里产生歧义,编译器会报错
    }
    

    相关文章

      网友评论

        本文标题:kotlin中的二元运算符重载

        本文链接:https://www.haomeiwen.com/subject/kecprftx.html