Kotlin进阶语法之操做符重载与中缀调用

操做符

首先要清楚常见的操做符有哪些?数组

对一元操做符来讲包括'!'、'++'、'--',咱们经常使用的是非操做和自增操做。bash

咱们更熟悉二元操做符,好比a + b在这个场景下'+'就是二元操做符,常见的二元操做符就是加减乘除等算术符号。ide

在Kotlin中还增长了其余二元操做符,好比:in/!in(范围操做符)。函数

另外还有一些其余的操做符,好比索引访问操做符a[i]、调用操做符a()。测试

操做符重载

你是否想过相似println("s" + 1)这样的代码为什么会编译经过,一个String类型和一个Int类型是如何相加的?为何String类型能够像数组同样能够经过下标访问字符sss[1]ui

没错,不管'+' 仍是取索引都是一种操做符,Kotlin支持操做符的重载,也就是能够将不一样类型的对象进行算术运算或其它运算。this

咱们看看Kotling中String的源码。spa

public class String : Comparable<String>, CharSequence {
    companion object {}
    
    //+操做符重载
    public operator fun plus(other: Any?): String

    //索引访问操做符重载
    public override fun get(index: Int): Char
    ...
}
复制代码

操做符重载方法需声明operator关键字,plus方法对应'+'操做符,参数声明为Any?,可见正式由于String重载了'+'操做符,且参数为Any?,因此在代码中能够用一个String类型的对象"+" 任意一个对象。code

接下来看一下操做符对应的重载方法名。对象

一元操做符 对应方法
+a a.unaryPlus()
-a a.unaryMinus()
!a a.not()
a++/++a a.inc()
a--/--a a.dec()
二元操做符 对应方法
a + b a.plus(b)
a - b a.minus(b)
a * b a.times(b)
a / b a.div(b)
a % b a.rem(b)
a..b a.rangeTo(b)
a in b b.contains(a)
a !in b !b.contains(a)
a > b a.compareTo(b) > 0

回到上面的例子,若是咱们稍微调整一下代码 println(1+"s")这样就会编译报错,能够想见Int类并不支持plus且参数为String的重载。 咱们看一下Int类关于plus的重载函数。

# Int
/** Adds the other value to this value. */
public operator fun plus(other: Byte): Int
/** Adds the other value to this value. */
public operator fun plus(other: Short): Int
/** Adds the other value to this value. */
public operator fun plus(other: Int): Int
/** Adds the other value to this value. */
public operator fun plus(other: Long): Long
/** Adds the other value to this value. */
public operator fun plus(other: Float): Float
/** Adds the other value to this value. */
public operator fun plus(other: Double): Double
复制代码

经过重载函数的声明能够确认Int类型只能与一个数字相 '+'。

接下来咱们举几个例子加深理解。

class Number constructor(var value: Int)

// 重载一元操做符+,使其对Number中实际数据取绝对值
operator fun Number.unaryPlus(): Number {
    this.value = Math.abs(value)
    return this
}

// 非运算取相反数 
operator fun Number.not(): Number {
    this.value = -value
    return this
}

// 重载Number类的加法运算符 但并不作真正的加法
operator fun Number.plus(value: Int): Number {
    return Number(this.value)
}

// 重载Number类的加法运算符 支持Number类型
operator fun Number.plus(value: Number): Number {
    return Number(this.value)
}

// 重载Number类的索引运算 返回某个位上的数字
operator fun Number.get(index: Int): Int {
    return this.value / Math.pow(10.toDouble(), index.toDouble()).toInt() % 10
}
复制代码

测试函数

@JvmStatic
fun main(args: Array<String>) {

    val number1 = Number(-3)
    val number2 = Number(2)
    println("Number value = ${number1.value}")
    println("一元加法运算 value = ${(+number1).value}")
    println("二元加法运算 value = ${(number1 + number2).value}")

    val number3 = Number(876543210)
    println("索引 number3 = ${number3[6]}")
}

//输出
Number value = -3
一元加法运算 value = 3
二元加法运算 value = 3
索引 number3 = 6
复制代码

中缀调用

上面的例子都比较好理解,操做符也是咱们常见的,试想一下Kotlin是否支持自定义的操做符呢?回答是确定的,它是Kotlin语言的一大特性。

来看一个栗子:

//定义String1类
class String1(var str: String)
//声明中缀调用符"love"
infix fun String1.love(other: String1): String {
//    return this.str + "love" + other.str//理想状况
    return if(other.str == "you") "gun" else "meizizi" //实际状况
}
复制代码

使用infix关键字声明中缀函数,中缀符为'love',根据传入参数判断返回值,只要不是'you',都是美滋滋。若是是'you',心拔凉拔凉的。另需注意中缀函数也是扩展函数的一种,需在顶层包内声明。

来测试一下看看效果。

@JvmStatic
fun main(args: Array<String>) {
    val I = String1("i")
    val YOU = String1("you")
    //两个String1类型之间支持中缀符'love'
    print(I love YOU)
}
//输出 gun
复制代码
相关文章
相关标签/搜索