美文网首页我的Kotlin之旅Android知识Android开发经验谈
Kotlin学习(十三): 集合(Collections)和范围

Kotlin学习(十三): 集合(Collections)和范围

作者: 叫我旺仔 | 来源:发表于2017-06-19 10:06 被阅读980次
    Kotlin

    集合(Collections)

    Kotlin的集合类型和Java不一样,Kotlin的集合分为可变(读写)和不可变(只读)类型(lists, sets, maps, etc),可变类型是在不可变类型前面加Mutable

    • List<out E>MutableList<E>
    • Set<out E>MutableSet<E>
    • Map<K, out V>MutableMap<K, V>

    举个栗子:

    val numbers: MutableList<Int> = mutableListOf(1, 2, 3)
    val readOnlyView: List<Int> = numbers
    println(numbers)        // prints "[1, 2, 3]"
    numbers.add(4)
    println(readOnlyView)   // prints "[1, 2, 3, 4]"
    // readOnlyView.clear()    // 报错
    
    val strings = hashSetOf("a", "b", "c", "c")
    assert(strings.size == 3)
    

    为什么加了Mutable前缀就是可变类型?

    Collections

    我们先来看List,List实现了Collection接口,而MutableList实现的是List和MutableCollection接口

    Collection MutableCollection

    可以看出,MutableCollection接口实现了Collection接口,并且在里面添加了addremove等操作方法,
    所以加了Mutable前缀就是可变类型,而没有的就是不可变类型。

    创建集合

    Kotlin没有用于创建列表或集合的专用语法结构,只能使用标准库中的方法:listOf(), mutableListOf(), setOf(), mutableSetOf(),mapOf()等等。

    // 等同于Java的List<String> list = new ArrayList();
    val list: List<String> = arrayListOf()
    val mutableList: MutableList<String> = mutableListOf()
    // 也可以这样写
    val list2 = mutableListOf<String>()
    val mutableList2 = mutableListOf<String>()
    
    // 等同于Java的Map<String, String> map = new HashMap();
    val map: Map<String, String> = mapOf()
    val mutableMap: MutableMap<String, String> = mutableMapOf()
    // 也可以这样写
    val map2 = mapOf<String, String>()
    val mutableMap2 = mutableMapOf<String, String>()
    

    其中mapOf()可以简写成mapOf(a to b, c to d)

    val map: Map<Int, Int> = mapOf(1 to 1, 2 to 2)
    

    范围(Ranges)

    范围表达式由rangeTo函数形成,操作符形式为..,由in!in进行连接,可以用于判断,也可用于循环当中:

    if (i in 1..10) { // i in 1..10 等同于1 <= i && i <= 10
        println(i) 
    }
    

    为什么..能够替换rangeTo函数,这就涉及到运算符的重载了。

    运算符重载

    rangeTo

    Kotlin提供了一些运算符,这些运算符有固定的符号表示形式(如+-),运算符重载要在函数加operator关键字,在使用直接用运算符来替换函数,如..替换rangeTo函数:

    if (i in 1..10) { 
        println(i) 
    }
    // 等同与
    if (i in 1.rangeTo(10)) {
        println(i) 
    }
    

    常见运算符

    +%in==等等,都是运算符重载。

    前缀运算符
    递增和递减
    算术运算符
    in!in运算符
    索引访问操作符
    调用运算符
    赋值(Augmented assignments)

    注意:赋值在 Kotlin 中不是表达式。

    等式运算符

    注意:===!==没有被重载

    比较运算符

    针对Int类型,是去调用compareTo函数来比较

    范围(Ranges)

    范围表达式由rangeTo函数形成,操作符形式为..,由in!in进行连接,可以用于判断,也可用于循环当中:

    if (i in 1..10) { // i in 1..10 等同于1 <= i && i <= 10
        println(i) 
    }
    

    简写

    (1..10).forEach { print(it) }
    

    为什么..能够替换rangeTo函数,这就涉及到运算符的重载了。

    运算符重载

    rangeTo

    运算符重载要在函数加operator关键字,

    Ranges是如何运行的

    Ranges包含三种IntRangeLongRangeCharRange,都是实现了通用接口ClosedRange<T>

    ClosedRange

    ClosedRange<T>表示在数学意义上的闭区间,定义为可比较类型,具有两个端点startendInclusive,以及包含的范围,用in!in来进行操作。

    Progression

    Ranges在实现ClosedRange<T>的同时,也分别继承了相对应的运算进度类,如IntRange继承了IntProgression类,由first元素,last元素和不为零的step来定义,第一个元素是first元素,后面的元素是上一个元素加上step的结果。

    Iterable

    Progression进度类是Iterable<T>的子类,T包括IntLongChar三种类型,这就是Ranges可以用于for循环和map/filter等函数。

    fromClosedRange

    Progression进度类中,有个伴生对象里面的函数fromClosedRange用来构建进度。

    总结下,..操作符创建一个实现了ClosedRange <T>和继承了*Progression的对象。例如IntRange实现了ClosedRange <Int>接口,并继承了IntProgression类,因此为IntProgression里面的所有操作都可用在IntRange

    常用函数

    Ranges的函数基本都是扩展函数。

    rangeTo()

    rangeTo

    默认的rangeTo是正序的,如果将1..10改为10..1的话,上面的循环是不会执行的:

    for (i in 10..1) {
         println(i) // prints nothing
    }
    

    浮点数(FloatDouble)不能使用rangeTo操作,而是使用提供的通用Comparable类型的标准库:

    public operator fun <T: Comparable<T>> T.rangeTo(that: T): ClosedRange<T>
    

    该方法不能用于循环迭代(for循环等等)。

    downTo()

    downTo

    downTo()在是扩展函数的同时,也是中缀函数,使用downTo()函数控制倒序输出:

    for (i in 10 downTo 1) {
         println(i) // 打印10987654321
    }
    

    简写

    (10 downTo 1).forEach { print(it) } // 打印10987654321
    

    step()

    step

    step()也是中缀函数,默认间隔长度是1,如果要自定义间隔长度的话,就要使用step()函数:

    for (i in 1..4 step 2) print(i) // 打印"13"
    
    for (i in 4 downTo 1 step 2) print(i) // 打印"42"
    

    简写

    (1..4 step 2).forEach { print(it) } // 打印"13"
    (4 downTo 1 step 2).forEach { print(it) } // 打印"42"
    

    until()

    until

    until()也是中缀函数,要创建不包含其终端元素的范围,可以使用until()函数:

    for (i in 1 until 10) { // i in [1, 10), 打印123456789
         println(i)
    }
    

    简写

    (1 until 10).forEach { print(it) } // 打印123456789
    

    reversed()

    reversed

    reversed()函数,功能同单词,反向,由于reversed()并不是中缀函数,所以写法跟上面的那些不一样:

    for (i in (1..4).reversed())
         print(i) // print 4321
    

    简写

    (1..4).reversed().forEach { print(it) } // print 4321
    

    相关文章

      网友评论

        本文标题:Kotlin学习(十三): 集合(Collections)和范围

        本文链接:https://www.haomeiwen.com/subject/tfszxxtx.html