Kotlin 学习笔记07

Kotlin运算符重载与约定
本文深入探讨Kotlin中的运算符重载和约定,包括如何定义自定义运算符,如加法、减法、乘法等,并解释了一元运算符、赋值运算符、比较运算符的重载方式。同时,文章详细介绍了Kotlin中常见的约定,如使用下标访问元素、'in'关键字的约定、区间约定以及如何自定义迭代器。

运算符重载和其他约定

  • 通过调用自己代码定义函数,实现特定语言结构 比如在类中定义一个plug的方法,按照约定你就可以在该类实例中使用+ 运算符。
  • 常见于把约定方法定义成拓展函数以适应现有的类。
data class Point(val x: Int, val y: Int)
operator fun Point.plus(other: Point) = Point(x + other.x, y + other.y) //使用拓展函数 签名必须加operator
复制代码

在Kotlin中不能定义自己的运算符,提供的二元运算符有:

表达式运算符
b * Atimes
a/bdevis
a%bmod
a+bplugs
a-bminus

Kotlin 运算符不会自动支持交互\

  • 定义一个返回值结果不一样的运算符
operator fun Char.times(num: Int) = toString()+num //这里定义 左边是Char,右边是Int,返回结果是String值
//这里很明显是不能调换的。
复制代码
  • 重载符合赋值运算符 比如 +=
    munisAssign timeAssign +=可以用+号连接表示。

  • 重载一元运算符
operator fun Point.unaryMinus() = Point(-x , -y )
//调用
println(-Point(10,10))//得到的结果 Point(-10,-10)
复制代码
  • 对应的一元运算符约定
表达式函数名
+aunnaryPlus
-aunnaryMunus
!anot
++ainc
--adec
  • 重载比较运算符: “equls
    a==b -> a?equls(b)?:(b==null) 恒等运算符=== 与Java中的“==” 是一样的。

  • 排序运算符: compareTo 在Java中,这里这个排序算法用于查找最大值或者排序时候使用,必须要明确标记p1.compareTo(p2)<0,等价于Kotlin中p1<p2

data class Person(val name: String, val age: Int) : Comparable<Person> {
    override fun compareTo(other: Person): Int {
        return compareValuesBy(this, other, Person::name, Person::age)
    }
}
复制代码
集合和区间约定
  • 使用下标访问元素“get”和“set” a[b] 下标运算符
    val value = map[key]
    也可以这样设置元素
    mutablemap[key] = newValue
    如果你需要实现一个二维矩阵可以这样写:
operator fun xx.get(rowIndex: Int,colIndex: Int)
//调用
xx[10,11]
复制代码
  • "in"的约定函数 contails
data class Rectangle(val upperLeft: Point, val lowerRight: Point)

operator fun Rectangle.contains(p: Point): Boolean {
    return p.x in upperLeft.x until lowerRight.x &&
            p.y in upperLeft.y until lowerRight.y
}
//调用
Point(10,10) in Rectangle(Point(2,2),Point(20,20))//true
复制代码
  • rangeTo的约定 区间约定..
public operator fun <T : Comparable<T>> T.rangeTo(that: T): ClosedRange<T> = ComparableRange(this, that)

复制代码
val now = LocalDate.now()
println(now.plusDays(100) in now..now.plusWeeks(30))//true

(0..19).forEach { println("$it") }//也可以这样
复制代码
  • 在for循环中使用“iterator”的约定
    for(x in list){/**逻辑**/}
    in 被用于循环。for遍历字符串
for (letter in "abc") println("$letter")
复制代码

可以自定义iterator方法,使用for遍历:比如遍历日期

operator fun ClosedRange<LocalDate>.iterator(): Iterator<LocalDate> = object : Iterator<LocalDate> {
    var current = start
    override fun hasNext() = current <= endInclusive
    override fun next() = current.apply { current = current.plusDays(1) }
}

//调用
val now = LocalDate.now()
for (localDate in (now..now.plusDays(10))) {
    println(localDate.atStartOfDay())
}
复制代码

结构声明和组件函数

允许你展开单个复合值

data class Point(val x: Int, val y: Int)
val (x, y) = Point(10, 22)
println(x)//10
println(y)//20
复制代码

需要用到约定原理,要在结果声明中初始化每一个变量,将调用名为componentN的函数,其中N是声明中的声明变量。

data修饰的class已经自动帮生成了这样的定义,所以不需要手动设置。
使用场景:
从一个函数返回多个值,这个很有用。eg

data class NameComponent(val name: String, val extension: String)
fun getFileName(fullName: String): NameComponent{
    val split = fullName.split('.', limit = 2)
    return NameComponent(split[0],split[1])
}
//调用
val (fileName,extension) = getFileName("kotlin.txt")
println(fileName)//kotlin
println(extension)//txt
复制代码

让一个函数返回多个值还可以用标准库中的Pair
在for循环中使用解构

val map = mapOf(2 to "11", 12 to "88", 0 to "99")//注意 标准库中,map是实现了component1,component2
//@kotlin.internal.InlineOnly
//public inline operator fun <K, V> Map.Entry<K, V>.component1(): K = key
//@kotlin.internal.InlineOnly
//public inline operator fun <K, V> Map.Entry<K, V>.component2(): V = value
for((key,value) in map){
    println("key = $key,value = $value")
}
复制代码

重用属性访问的逻辑:委托属性
  • 操作对象不用自己执行,而是把工作委托给其他的一个辅助对象。称为:委托 一个标准的属性委托如下:
class foo {
    private var delegate = Delegate()
    var p: Type
        get() = delegate.get
        set(value) = delegate.set(value)
}
复制代码
  • 惰性初始化by lazy() 第一次访问该属性才会根据需要创建。跟单例的懒汉模式是一样的 使用标准库函数by lazy() 会简洁很多
data class Person(val name: String, val age: Int) {
    val emails by lazy { sendEmail(emails) }
}
复制代码
  • 通过by关键字,编译器会自动生成委托的模版代码
    Delegates.observable 函数可以用来添加属性更改的观察者。
//定义一个Person类
class Person(val name: String, age: Int, salary: Int) : PropertyChangeAware() {
    val observer = { prop: KProperty<*>, oldValue: Int, newValue: Int -> changeSupport.firePropertyChange(prop.name, oldValue, newValue) }

    var age :Int by Delegates.observable(age,observer)//Delegates.observable 函数可以用来添加属性更改的观察者。
    var salary :Int by Delegates.observable(salary,observer)
}

//定义一个监听类
open class PropertyChangeAware {
    protected val changeSupport = PropertyChangeSupport(this)

    fun addPropertyChangeListener(listener: PropertyChangeListener) = changeSupport.addPropertyChangeListener(listener)

    fun removePropertyListener(listener: PropertyChangeListener) = changeSupport.removePropertyChangeListener(listener)
}
//调用
val person = Person("Bob", 18, 20000)
person.addPropertyChangeListener(
        PropertyChangeListener { evt ->
            println("Property ${evt.propertyName} change from ${evt.oldValue} to ${evt.newValue}")
        }
)
person.age = 19
复制代码
  • 在map中保存属性值
class Pepole {
    private val _attributes = hashMapOf<String, String>()
    fun setAttribute(attrName: String, value: String) {
    _attributes[attrName] = value
    }
    val name: String by _attributes
}
复制代码
框架中的委托属性

End

转载于:https://juejin.im/post/5c3b101d51882525025d4bf7

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值