相信学过C++/Kotlin等支持运算符重载语言的同志们都知道运算符重载在代码编写过程中是十分方便的,举个反例:
Java无法在代码层面实现运算符重载,所以大整数之类的使用起来就稍显繁杂:
1 | BigInteger num1 = new BigInteger("12456"); |
很显然一个简单的乘法运算被复杂化了,如果是支持运算符重载:
1 | BigInteger num1 = "12456"; |
这样用起来方便多了,所以结绳4.0支持了运算符重载,并且不受任何目标平台影响
1 | 变量 坐标1 : 坐标 = (1, 2) |
可以注意到,赋值运算符=与其他二元运算符是不一样的,所以=需要特殊实现,
了解语法树的同志们都知道,二元运算(Binary)一般都是这样的结构:
1 | Left |
再来看方法调用(MethodInvocation)的结构:
1 | Selector |
如果我们仔细想一想会发现,MethodInvocation可以是一个Operator固定为句点运算符’.’的Binary,
Selector为Binary的Left,MethodName为Binary的Right,
那么在进行语法树标注的时候,当在标注二元运算式时,就可以查找左值或右值中是否存在对应运算符的重载方法,
如果有就将当前二元运算式修改为方法调用表达式,这样就轻松实现运算符重载了。
我们再来看下面一段代码(伪代码):
1 | class Coordinate |
结绳4.0要支持多个目标平台,那么结绳到底是如何实现对赋值运算符重载的呢?
其实很简单,所有面向对象的语言都有一个共性,肯定有方法/函数,如何让重载=时是去调用方法,那就肯定好做多了
实现过程:
首先,了解语法树的同志都知道,在进行语法树标注的时候会标注到赋值表达式(Assignment),
这时就可以判断左值所对应类型中是否具有对=的重载方法,如果有就将该赋值表达式的右值修改为一个方法调用(MethodInvocation)表达式,
并将原来的赋值作为该方法调用表达式的参数,由此就能轻松地实现对=的重载
【题外话】
我翻阅了Javac(Java编译器)的源代码,发现它其实也是支持运算符重载的,
不过只能在编译器内部定义重载(所以上面我说的是无法在代码层面实现运算符重载,并不是说不支持运算符重载),具体实现方式与结绳4.0相差不大