Kotlin集合与区间的约定
1.通过下标来访问元素:get和set
在kotlin中我们可以用类似java中数组的方式来访问map中的元素,如:
val value=map[key]
也可以用同样的运算符来改变一个可变的元素,如:
mutableMap[key]=newValue
在kotlin中读取元素默认转换为get运算符方法调用,设置元素默认转换为set运算符方法调用。
1.1实现get约定
我们尝试用数组的方式去访问一个二维点的x,y值
operator fun Point.get(index:Int):Int{
return when(index){
0->x
1->y
else->throw IndexOutOfBoundsException("Invalid coordinate $index")
}
}
测试
P[1]//20
P[3]//java.lang.IndexOutOfBoundsException: Invalid coordinate 3
我们所做的工作就是定义一个名为get的函数,并标记为operator后,就可以用像p[1]的方式去访问内容。get函数的参数可以定位为任何类型,例如你可以用color["black"]
operator fun Colors.get(name:String):String{
return when(name){
"white"->"#fff"
"black"->"#000"
else->throw error("not color")
}
}
1.2实现set约定方法
data class MutablePoint(var x: Int, var y: Int)
operator fun MutablePoint.set(index: Int, value: Int) {
when (index) {
0 -> x = value
1 -> y = value
else -> throw IndexOutOfBoundsException("Invalid coordinate $index")
}
}
测试
val p = MutablePoint(10, 20)
p[1] = 42
p//(10,42)
和get约定一样定义set的函数,可直接用p[1]=42的方式赋值。
2.in的约定
Kotlin集合支持in运算符,用于检查某个对象是否属于集合。相应的函数是contains函数。
2.1实现in的约定
我们使用in运算符来检查点是否属于一个矩形。
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
}
测试
val rect = Rectangle(Point(10, 20), Point(50, 50))
Point(20,30) in rect//true
in右边的对象将会调用contains函数,in左边的对象将会作为函数入参。
我们用until构建了个开区间,不包含最后一个值,如(50,50)这个点就不在区间内。当然我们页可以用1..10 的形式来定义一个闭区间。
3.rangeTo的约定
Kotlin创建区间使用..语法,如1..10代表从1-10的一个闭区间包含1和10,..运算符调用的是rangeTo函数。
3.1处理日期的区间
val now=LocalDate.now()
val vacation=now..now.plusDays(10)//定义一个从今天开始到10天之后的闭区间
now.plusDays(1) in vacation//true
rangeTo是Comparable的一个拓展函数,rangeTo运算符的优先级低于算数运算符。
读取区间
(0..10).forEach { Log.e("TAG",it.toString()) }//1,2,3,4..10
在读取之前需要将区间用括号括起来才能调用。
4.在for循环中使用iterator的约定
在kotlin中,可以在for循环中使用in运算符,如for(x in list)将被转换为list.iteratior()的调用。
4.1实现日期区间迭代器
operator fun ClosedRange<LocalDate>.iterator(): Iterator<LocalDate> =
object : Iterator<LocalDate> {
var current = start
override fun next(): LocalDate = current.apply {
current = plusDays(1)
}
override fun hasNext() = current <= endInclusive
}
测试
val newYear = LocalDate.ofYearDay(2018, 1)
val daysOff = newYear.minusDays(1)..newYear
for (dayOff in daysOff) {
Log.e("TAG", dayOff.toString())//输出2017-12-31、2018-01-01
}