一、关于运算符的重载
kotlin的运算符重载和c++的运算符重载比较类似,使用operator的方式: operator fun xxx的方式
比如重载类Complex的乘号
data class Complex(val real: Int, val imaginary: Int) { operator fun times(other: Complex) = Complex(real * other.real - imaginary * other.imaginary, real * other.imaginary + imaginary * other.real) private fun sign() = if (imaginary < 0) "-" else "+" override fun toString() = "$real ${sign()} ${abs(imaginary)}i" } println(Complex(4, 2) * Complex(-3, 4)) println(Complex(1, 2) * Complex(-3, 4))
如上所示,重载了两个Complex的乘法,使用times
具体关于各个运算符对应的重载方法名如下所示
如上所示,每个运算符均有对应的运算符重载方法;
那么可能有疑问了,为何kotlin不能完全像c++一样,加号就使用operator fun +() 而是使用了plus呢
是因为:JVM不支持运算符重载(而且kotlin编译成java字节码),kotlin通过将运算符映射到特殊命名的方法,使运算符重载成为可能。
二、使用扩展函数注入运算符的方式
1、扩展函数使用运算符
operator fun Pair<Int, Int>.plus(other: Pair<Int, Int>) = Pair(first + other.first, second + other.second)
如上所述,虽然plus函数在Pair的类外面,但是我们在该位置可以使用加号对两个Pair进行相加
2、使用in运算符
data class Point(val x: Int, val y: Int) data class Circle(val cx: Int, val cy: Int, val radius: Int) operator fun Circle.contains(point: Point) = (point.x - cx) * (point.x - cx) + (point.y - cy)*(point.y - cy) < radius * radius val circle = Circle(100, 100, 25) val point1 = Point(110, 110) println(circle.contains(point1)) println(point1 in circle)
如上所示,通过增加operator标识符,使得contains可以使用in来表示,更像自然语言
如果打算使用中缀表达式,则可以使用infix 关键字:如下所示
infix fun Circle.contains(point: Point) = (point.x - cx) * (point.x - cx) + (point.y - cy)*(point.y - cy) < radius * radius println(circle contains point1)
如上所示,则是实用中缀的方式;如果要同时使用operator和infix也是可以的:operator infix fun Circle.contains(point: Point) = 。。。。。
三、关于四种方法的行为:let、also、run、apply
先总结各个方法的用法:
let:有一个context参数,并返回对应的计算结果
also:有一个context参数,并返回context参数
run:无参数,返回结果
apply:无参数,并返回context
》》个人理解:context即使用this,更细节的就不去深究了
例子,如下为了计算,只使用了from和send两个函数:
class Mailer { val details = StringBuilder() fun from(addr: String) = details.append("from $addr...\n")
fun to(addr: String) = details.append("to $addr...\n") fun send() = "...sending...\n$details" }
正常的调用逻辑:
val mailer = Mailer() mailer.from("[email protected]") // 先构造完,这里为了简单只使用from构造,其实还有to,body等构造
mailer.to("[email protected]") val result = mailer.send() println(result)
但是我们可以使用apply进行简化代码
val mailer1 = Mailer() .apply{from("[email protected]")} .apply{to("[email protected]")} val result1 = mailer1.send() println(result1)
因为apply是无参,并且返回this,所以可以调用多个;我们也可以将上述的两个apply合并
val mailer1 = Mailer() .apply { from("[email protected]") to("[email protected]") }
那么如果要将send也合并到一起呢? 因为send是返回String类型所以可以使用run的方式
val result2 = Mailer().run { from("[email protected]") to("[email protected]") send() } println(result2)
如上,通过最后send返回的是String,返回给result2
同理,let和also也是差不多,只是let会将this作为参数传给lambda
四、关于隐式接收方
var length = 100 val printIt: (Int) -> Unit = {n: Int -> println("n is $n, length is $length") } printIt(6)
如上函数的打印结果是:n is 6, length is 100
但是我们如果要打印字符串的长度,则可以使用隐式的方式
val printIt: String.(Int) -> Unit = {n: Int -> println("n is $n, length is ${this.length}") } printIt("Hello", 6) "Hello".printIt(6)
如上的两种方式均能否正常调用printIt函数,并且返回的结果是一样的
标签:val,point,Int,kotlin,运算符,println,流畅性,fun From: https://www.cnblogs.com/czwlinux/p/16891040.html