美文网首页Kotlinkotlin频道Kotlin程序设计
《Kotlin 程序设计》第四章 Kotlin 语法基础

《Kotlin 程序设计》第四章 Kotlin 语法基础

作者: 光剑书架上的书 | 来源:发表于2017-05-29 03:37 被阅读210次

    第四章 Kotlin 语法基础

    正式上架:《Kotlin极简教程》Official on shelves: Kotlin Programming minimalist tutorial
    京东JD:https://item.jd.com/12181725.html
    天猫Tmall:https://detail.tmall.com/item.htm?id=558540170670

    定义包

    包的声明应处于源文件顶部:

    package my.demo
    
    import java.util.*
    
    // ……
    

    目录与包的结构无需匹配:源代码可以在文件系统的任意位置。

    定义函数

    完整的 Kotlin 方法定义语法为

    [访问控制符] fun 方法名(参数列表) [:返回值类型] {}
    

    Kotlin 可以省略变量定义的类型声明,但是在定义参数列表和定义返回值类型时则必须明确指定类型(这个类型推断Kotlin居然没做,这地方用起来比Scala,Groovy要繁琐点)。

    例如,定义一个带有两个 Int 参数、返回 Int 的函数:

    
    fun sum(a: Int, b: Int): Int { // kotlin中的返回值类型必须明确指定
        return a + b
    }
    
    fun main(args: Array<String>) {
        print("sum of 3 and 5 is ")
        println(sum(3, 5))
    }
    

    将表达式作为函数体、返回值类型自动推断的函数:

    fun sum(a: Int, b: Int) = a + b
    fun main(args: Array<String>) {
        println("sum of 19 and 23 is ${sum(19, 23)}")
    }
    

    函数返回无意义的值:

    fun printSum(a: Int, b: Int): Unit {
        println("sum of $a and $b is ${a + b}")
    }
    fun main(args: Array<String>) {
        printSum(-1, 8)
    }
    

    Unit 返回类型可以省略:

    fun printSum(a: Int, b: Int) {
        println("sum of $a and $b is ${a + b}")
    }
    fun main(args: Array<String>) {
        printSum(-1, 8)
    }
    

    变长参数函数

    同 Java 的变长参数一样,Kotlin 也支持变长参数

    //在Java中,我们这么表示一个变长函数
    public boolean hasEmpty(String... strArray){
        for (String str : strArray){
            if ("".equals(str) || str == null)
                return true;
        }
        return false;
    }
    

    //在Kotlin中,使用关键字vararg来表示

    fun hasEmpty(vararg strArray: String?): Boolean{
        for (str in strArray){
            if ("".equals(str) || str == null)
                return true 
        }
        return false
    }
    

    定义局部变量

    使用val 定义一次赋值(只读)的局部变量:

    fun main(args: Array<String>) {
        val a: Int = 1  // 立即赋值
        val b = 2   // 自动推断出 `Int` 类型
        val c: Int  // 如果没有初始值类型不能省略
        c = 3       // 明确赋值
        println("a = $a, b = $b, c = $c")
    }
    

    使用var定义可变变量:

    fun main(args: Array<String>) {
    
        var x = 5 // 自动推断出 `Int` 类型
        x += 1
    
        println("x = $x")
    }
    

    代码注释

    正如 Java 和 JavaScript,Kotlin 支持行注释及块注释。

    // 这是一个行注释
    
    /* 这是一个多行的
       块注释。 */
    

    与 Java 不同的是,Kotlin 的块注释可以嵌套。就是说,你可以这样注释:

    /**
     * hhhh
     * /**
     *  fff
     *  /**
     *    ggggg
     *  */
     * */
     *
     * abc
     *
     */
    fun main(args:Array<String>){
        val f = Functions()
        println(f.fvoid1())
        println(f.fvoid2())
        println(f.sum1(1,1))
        println(f.sum2(1,1))
    }
    
    

    main函数

    Kotlin 程序的入口是名为"main"的函数。命令行参数通过这个方法的数组参数传递。

    代码示例:

    fun main(args: Array<String>) {}
    

    变量声明

    Kotlin声明变量可以用var或者 val
    val声明的参数不能重新赋值(只读),但用var声明的可以(可写)。

    代码示例:

        val fooVal = 10 // 不能再赋别的值给fooVal
        //fooVal = 11 // Val cannot be reassigned
        var fooVar = 10
        fooVar = 20 // fooVar可以重新赋值
    

    其中,var fooVar = 10变量声明我们并没有指定变量的类型。

    大部分情况下,Kotlin 可以判断变量的类型,所以不用每次都显式声明。
    我们也可以像下面这样显式声明一个变量的类型:

        val foo: Int = 7
    

    使用is 运算符进行类型检测

    is 运算符检测一个表达式是否某类型的一个实例。

    如果一个不可变的局部变量或属性已经判断出为某类型,那么检测后的分支中可以直接当作该类型使用,无需显式转换:

    fun getStringLength(obj: Any): Int? {
        if (obj is String) {
            // `obj` 在该条件分支内自动转换成 `String`
            return obj.length
        }
    
        // 在离开类型检测分支后,`obj` 仍然是 `Any` 类型
        return null
    }
    
    
    fun main(args: Array<String>) {
        fun printLength(obj: Any) {
            println("'$obj' string length is ${getStringLength(obj) ?: "... err, not a string"} ")
        }
        printLength("Incomprehensibilities")
        printLength(1000)
        printLength(listOf(Any()))
    }
    

    或者

    fun getStringLength(obj: Any): Int? {
        if (obj !is String) return null
    
        // `obj` 在这一分支自动转换为 `String`
        return obj.length
    }
    
    
    fun main(args: Array<String>) {
        fun printLength(obj: Any) {
            println("'$obj' string length is ${getStringLength(obj) ?: "... err, not a string"} ")
        }
        printLength("Incomprehensibilities")
        printLength(1000)
        printLength(listOf(Any()))
    }
    

    或者

    fun getStringLength(obj: Any): Int? {
        // `obj` 在 `&&` 右边自动转换成 `String` 类型
        if (obj is String && obj.length >= 0) {
            return obj.length
        }
    
        return null
    }
    
    
    fun main(args: Array<String>) {
        fun printLength(obj: Any) {
            println("'$obj' string length is ${getStringLength(obj) ?: "... err, is empty or not a string at all"} ")
        }
        printLength("Incomprehensibilities")
        printLength("")
        printLength(1000)
    }
    

    字符串

    原始字符串(raw string)由三重引号(""")分隔(这个跟python一样)。原始字符串可以包含换行符和任何其他字符。

        val fooRawString = """
    fun helloWorld(val name : String) {
       println("Hello, world!")
    }
    """
        println(fooRawString)
    

    字符串可以包含模板表达式。模板表达式以美元符号($)开始。

        val fooTemplateString = "$fooString has ${fooString.length} characters"
        println(fooTemplateString)
    

    if表达式

    /**
     * `if` is an expression, i.e. it returns a value.
     * Therefore there is no ternary operator (condition ? then : else),
     * because ordinary `if` works fine in this role.
     * See http://kotlinlang.org/docs/reference/control-flow.html#if-expression
     */
    fun main(args: Array<String>) {
        println(max(args[0].toInt(), args[1].toInt()))
    }
    
    fun max(a: Int, b: Int) = if (a > b) a else b
    

    另外,在Kotlin中没有类似true? 1: 0这样的三元表达式。对应的写法是使用if else语句:

    if(true) 1 else 0
    

    when表达式

    when表达式类似于Java中的switch。 代码示例:

    fun cases(obj: Any) {
        when (obj) {
            1 -> print("第一项")
            "hello" -> print("这个是字符串hello")
            is Long -> print("这是一个Long类型数据")
            !is String -> print("这不是String类型的数据")
            else -> print("else类似于Java中的default")
        }
    }
    
    
    
    

    空对象检查Null Check

    fun Any?.toString(): String
    

    要使变量保持为null,必须将其显式指定为可空: 在变量类型后面加上? 符号,即声明为可空。

    ?. 运算符来访问一个可空的变量。
    ?: 运算符来指定当该变量为空时的替代值

    代码示例:

    
    package com.easy.kotlin
    
    /**
     * Created by jack on 2017/5/30.
     */
    
    fun main(args: Array<String>) {
        val s: String? = null
        println(s?.length)
    
        var fooNullable: String? = "abc"
        println(fooNullable?.length) // => 3
        println(fooNullable?.length ?: -1) // => 3
        fooNullable = null
        println(fooNullable?.length) // => null
        println(fooNullable?.length ?: -1) // => -1
    
        testNullSafeOperator(null)
        testNullSafeOperator("12345678901")
        testNullSafeOperator("123")
    
    }
    
    
    fun testNullSafeOperator(string: String?) {
        println(string?.toCharArray()?.getOrNull(10)?.hashCode())
    }
    
    fun toString(any:Any): String{
      return any?.toString()
    }
    
    
    

    这个null check是怎样实现的呢?

    我们来看一下Kotlin ByteCode。打开IDEA->Tool->Kotlin->Show Kotlin ByteCode:

    我们可以看到上面的Kotlin源码对应的字节码如下:

    // ================com/easy/kotlin/NullCheckKt.class =================
    // class version 50.0 (50)
    // access flags 0x31
    public final class com/easy/kotlin/NullCheckKt {
    
    
      // access flags 0x19
      public final static main([Ljava/lang/String;)V
        @Lorg/jetbrains/annotations/NotNull;() // invisible, parameter 0
        ACONST_NULL
        CHECKCAST java/lang/String
        ASTORE 1
       L0
        ALOAD 1
        ASTORE 2
       L1
        ALOAD 2
        ACONST_NULL
        INVOKESTATIC kotlin/jvm/internal/Intrinsics.areEqual (Ljava/lang/Object;Ljava/lang/Object;)Z
        IFEQ L2
        ACONST_NULL
        CHECKCAST java/lang/Integer
        GOTO L3
       L2
        ALOAD 2
        INVOKEVIRTUAL java/lang/String.length ()I
        INVOKESTATIC java/lang/Integer.valueOf (I)Ljava/lang/Integer;
       L3
        INVOKESTATIC kotlin/io/ConsoleKt.println (Ljava/lang/Object;)V
        LDC "abc"
        ASTORE 2
       L4
        ALOAD 2
        ASTORE 3
       L5
        ALOAD 3
        ACONST_NULL
        INVOKESTATIC kotlin/jvm/internal/Intrinsics.areEqual (Ljava/lang/Object;Ljava/lang/Object;)Z
        IFEQ L6
        ACONST_NULL
        CHECKCAST java/lang/Integer
        GOTO L7
       L6
        ALOAD 3
        INVOKEVIRTUAL java/lang/String.length ()I
        INVOKESTATIC java/lang/Integer.valueOf (I)Ljava/lang/Integer;
       L7
        INVOKESTATIC kotlin/io/ConsoleKt.println (Ljava/lang/Object;)V
        ALOAD 2
        ASTORE 4
       L8
        ALOAD 4
        ACONST_NULL
        INVOKESTATIC kotlin/jvm/internal/Intrinsics.areEqual (Ljava/lang/Object;Ljava/lang/Object;)Z
        IFEQ L9
        ACONST_NULL
        CHECKCAST java/lang/Integer
        GOTO L10
       L9
        ALOAD 4
        INVOKEVIRTUAL java/lang/String.length ()I
        INVOKESTATIC java/lang/Integer.valueOf (I)Ljava/lang/Integer;
       L10
        ASTORE 3
       L11
        ALOAD 3
        ACONST_NULL
        INVOKESTATIC kotlin/jvm/internal/Intrinsics.areEqual (Ljava/lang/Object;Ljava/lang/Object;)Z
        IFEQ L12
        ICONST_M1
        GOTO L13
       L12
        ALOAD 3
        INVOKEVIRTUAL java/lang/Number.intValue ()I
       L13
        INVOKESTATIC kotlin/io/ConsoleKt.println (I)V
        ACONST_NULL
        CHECKCAST java/lang/String
        ASTORE 2
        ALOAD 2
        ASTORE 3
       L14
        ALOAD 3
        ACONST_NULL
        INVOKESTATIC kotlin/jvm/internal/Intrinsics.areEqual (Ljava/lang/Object;Ljava/lang/Object;)Z
        IFEQ L15
        ACONST_NULL
        CHECKCAST java/lang/Integer
        GOTO L16
       L15
        ALOAD 3
        INVOKEVIRTUAL java/lang/String.length ()I
        INVOKESTATIC java/lang/Integer.valueOf (I)Ljava/lang/Integer;
       L16
        INVOKESTATIC kotlin/io/ConsoleKt.println (Ljava/lang/Object;)V
        ALOAD 2
        ASTORE 4
       L17
        ALOAD 4
        ACONST_NULL
        INVOKESTATIC kotlin/jvm/internal/Intrinsics.areEqual (Ljava/lang/Object;Ljava/lang/Object;)Z
        IFEQ L18
        ACONST_NULL
        CHECKCAST java/lang/Integer
        GOTO L19
       L18
        ALOAD 4
        INVOKEVIRTUAL java/lang/String.length ()I
        INVOKESTATIC java/lang/Integer.valueOf (I)Ljava/lang/Integer;
       L19
        ASTORE 3
       L20
        ALOAD 3
        ACONST_NULL
        INVOKESTATIC kotlin/jvm/internal/Intrinsics.areEqual (Ljava/lang/Object;Ljava/lang/Object;)Z
        IFEQ L21
        ICONST_M1
        GOTO L22
       L21
        ALOAD 3
        INVOKEVIRTUAL java/lang/Number.intValue ()I
       L22
        INVOKESTATIC kotlin/io/ConsoleKt.println (I)V
        ACONST_NULL
        CHECKCAST java/lang/String
        INVOKESTATIC com/easy/kotlin/NullCheckKt.testNullSafeOperator (Ljava/lang/String;)V
        LDC "12345678901"
        INVOKESTATIC com/easy/kotlin/NullCheckKt.testNullSafeOperator (Ljava/lang/String;)V
        LDC "123"
        INVOKESTATIC com/easy/kotlin/NullCheckKt.testNullSafeOperator (Ljava/lang/String;)V
        RETURN
       L23
        LOCALVARIABLE tmp0_safe_receiver Ljava/lang/String; L1 L3 2
        LOCALVARIABLE tmp1_safe_receiver Ljava/lang/String; L5 L7 3
        LOCALVARIABLE tmp2_safe_receiver Ljava/lang/String; L8 L10 4
        LOCALVARIABLE tmp3_elvis_lhs Ljava/lang/Integer; L11 L13 3
        LOCALVARIABLE tmp4_safe_receiver Ljava/lang/String; L14 L16 3
        LOCALVARIABLE tmp5_safe_receiver Ljava/lang/String; L17 L19 4
        LOCALVARIABLE tmp6_elvis_lhs Ljava/lang/Integer; L20 L22 3
        LOCALVARIABLE s Ljava/lang/String; L0 L23 1
        LOCALVARIABLE fooNullable Ljava/lang/String; L4 L23 2
        MAXSTACK = 2
        MAXLOCALS = 5
    
      // access flags 0x19
      public final static testNullSafeOperator(Ljava/lang/String;)V
        @Lorg/jetbrains/annotations/Nullable;() // invisible, parameter 0
        ALOAD 0
        ASTORE 3
       L0
        ALOAD 3
        ACONST_NULL
        INVOKESTATIC kotlin/jvm/internal/Intrinsics.areEqual (Ljava/lang/Object;Ljava/lang/Object;)Z
        IFEQ L1
        ACONST_NULL
        CHECKCAST [C
        GOTO L2
       L1
        ALOAD 3
        INVOKESTATIC kotlin/text/StringsKt.toCharArray (Ljava/lang/String;)[C
       L2
        ASTORE 2
       L3
        ALOAD 2
        ACONST_NULL
        INVOKESTATIC kotlin/jvm/internal/Intrinsics.areEqual (Ljava/lang/Object;Ljava/lang/Object;)Z
        IFEQ L4
        ACONST_NULL
        CHECKCAST java/lang/Character
        GOTO L5
       L4
        ALOAD 2
        BIPUSH 10
        INVOKESTATIC kotlin/collections/ArraysKt.getOrNull ([CI)Ljava/lang/Character;
       L5
        ASTORE 1
       L6
        ALOAD 1
        ACONST_NULL
        INVOKESTATIC kotlin/jvm/internal/Intrinsics.areEqual (Ljava/lang/Object;Ljava/lang/Object;)Z
        IFEQ L7
        ACONST_NULL
        CHECKCAST java/lang/Integer
        GOTO L8
       L7
        ALOAD 1
        INVOKEVIRTUAL java/lang/Object.hashCode ()I
        INVOKESTATIC java/lang/Integer.valueOf (I)Ljava/lang/Integer;
       L8
        INVOKESTATIC kotlin/io/ConsoleKt.println (Ljava/lang/Object;)V
        RETURN
       L9
        LOCALVARIABLE tmp0_safe_receiver Ljava/lang/String; L0 L2 3
        LOCALVARIABLE tmp1_safe_receiver [C L3 L5 2
        LOCALVARIABLE tmp2_safe_receiver Ljava/lang/Character; L6 L8 1
        MAXSTACK = 2
        MAXLOCALS = 4
    
      // access flags 0x19
      public final static toString(Ljava/lang/Object;)Ljava/lang/String;
      @Lorg/jetbrains/annotations/NotNull;() // invisible
        @Lorg/jetbrains/annotations/NotNull;() // invisible, parameter 0
        ALOAD 0
        ASTORE 1
       L0
        ALOAD 1
        ACONST_NULL
        INVOKESTATIC kotlin/jvm/internal/Intrinsics.areEqual (Ljava/lang/Object;Ljava/lang/Object;)Z
        IFEQ L1
        ACONST_NULL
        CHECKCAST java/lang/String
        GOTO L2
       L1
        ALOAD 1
        INVOKEVIRTUAL java/lang/Object.toString ()Ljava/lang/String;
       L2
        ARETURN
       L3
       L4
        LOCALVARIABLE tmp0_safe_receiver Ljava/lang/Object; L0 L2 1
        MAXSTACK = 2
        MAXLOCALS = 2
    
      // access flags 0x19
      public final static <clinit>()V
        RETURN
       L0
        MAXSTACK = 0
        MAXLOCALS = 0
    }
    
    
    
    

    我们来单独看一下fun toString()的bytecode:

    public final static toString(Ljava/lang/Object;)Ljava/lang/String;
      @Lorg/jetbrains/annotations/NotNull;() // invisible
        @Lorg/jetbrains/annotations/NotNull;() // invisible, parameter 0
        ALOAD 0
        ASTORE 1
       L0
        ALOAD 1
        ACONST_NULL
        INVOKESTATIC kotlin/jvm/internal/Intrinsics.areEqual (Ljava/lang/Object;Ljava/lang/Object;)Z
        IFEQ L1
        ACONST_NULL
        CHECKCAST java/lang/String
        GOTO L2
    
    ...
    
    

    其中, ACONST_NULL 指令是把null压到栈顶。然后调用

    INVOKESTATIC kotlin/jvm/internal/Intrinsics.areEqual (Ljava/lang/Object;Ljava/lang/Object;)Z
    

    这里的kotlin/jvm/internal/Intrinsics.areEqual (Ljava/lang/Object;Ljava/lang/Object;)函数代码是:

    
        public static boolean areEqual(Object first, Object second) {
            return first == null ? second == null : first.equals(second);
        }
    
    

    反编译成Java代码,如下:

       @NotNull
       public static final String toString(@NotNull Object any) {
          Intrinsics.checkParameterIsNotNull(any, "any");
          return any != null?any.toString():null;
       }
    

    由字节码分析可见,其实所谓的空指针安全操作符, 其实就是在内部封装了判空逻辑,来确保不出现空指针。

    循环

    while循环:

    /**
     * `while` and `do..while` work as usual.
     * See http://kotlinlang.org/docs/reference/control-flow.html#while-loops
     */
    fun main(args: Array<String>) {
        var i = 0
        while (i < args.size)
            println(args[i++])
    }
    

    for循环

    
    /**
     * For loop iterates through anything that provides an iterator.
     * See http://kotlinlang.org/docs/reference/control-flow.html#for-loops
     */
    fun main(args: Array<String>) {
        for (arg in args)
            println(arg)
        // or
        println()
        for (i in args.indices)
            println(args[i])
    }
    
    

    枚举

    
    enum class Color(
            val r: Int, val g: Int, val b: Int
    ) {
        RED(255, 0, 0), ORANGE(255, 165, 0),
        YELLOW(255, 255, 0), GREEN(0, 255, 0), BLUE(0, 0, 255),
        INDIGO(75, 0, 130), VIOLET(238, 130, 238);
    
        fun rgb() = (r * 256 + g) * 256 + b
    }
    
    fun main(args: Array<String>) {
        println(Color.BLUE.rgb())
    }
    
    
    
    enum class Color {
        RED, ORANGE, YELLOW, GREEN, BLUE, INDIGO, VIOLET
    }
    
    fun getMnemonic(color: Color) =
        when (color) {
            Color.RED -> "Richard"
            Color.ORANGE -> "Of"
            Color.YELLOW -> "York"
            Color.GREEN -> "Gave"
            Color.BLUE -> "Battle"
            Color.INDIGO -> "In"
            Color.VIOLET -> "Vain"
        }
    
    fun main(args: Array<String>) {
        println(getMnemonic(Color.BLUE))
    }
    
    

    遍历Map

    
    /**
     *  Kotlin Standard Library provide component functions for Map.Entry
     */
    
    fun main(args: Array<String>) {
        val map = hashMapOf<String, Int>()
        map.put("one", 1)
        map.put("two", 2)
    
        for ((key, value) in map) {
            println("key = $key, value = $value")
        }
    }
    
    

    拼接字符串

    fun <T> joinToString(
            collection: Collection<T>,
            separator: String,
            prefix: String,
            postfix: String
    ): String {
    
        val result = StringBuilder(prefix)
    
        for ((index, element) in collection.withIndex()) {
            if (index > 0) result.append(separator)
            result.append(element)
        }
    
        result.append(postfix)
        return result.toString()
    }
    
    fun main(args: Array<String>) {
        val list = listOf(1, 2, 3)
        println(joinToString(list, "; ", "(", ")"))
    }
    
    
    

    集合类操作

    Kotlin的集合类有可变集合和不可变集合(lists、sets、maps 等)。精确控制集合的编辑权限,有助于消除 bug 和设计良好的 API。

    预先了解一个可变集合的只读视图和一个真正的不可变集合之间的区别是很重要的。

    Kotlin 的 List<out T> 类型是一个提供只读操作如 sizeget等的接口。和 Java 类似,它继承自 Collection<T> 进而继承自 Iterable<T>

    而改变 list 的方法是由 MutableList<T> 加入的。这一模式同样适用于 Set<out T>/MutableSet<T>Map<K, out V>/MutableMap<K, V>

    我们可以看下 list 及 set 类型的基本用法:

    val numbers: MutableList<Int> = mutableListOf(1, 2, 3)
    val readOnlyView: List<Int> = numbers
    println(numbers)        // 输出 "[1, 2, 3]"
    numbers.add(4)
    println(readOnlyView)   // 输出 "[1, 2, 3, 4]"
    readOnlyView.clear()    // -> 不能编译
    
    val strings = hashSetOf("a", "b", "c", "c")
    assert(strings.size == 3)
    
    
    
    fun kotlin(ktFile: String): MutableList<String> {
            val result = mutableListOf<String>()
    
            kotlinc(ktFile)
    
            val ktClass = " " + ktFile.substring(0, ktFile.indexOf(".kt")) + "Kt"
            println(ktClass)
            val kotlin = KotlinBin.KOTLIN.binPath + ktClass
            println(kotlin)
            val runtime: Runtime = Runtime.getRuntime()
            val process: Process = runtime.exec(kotlin)
            val exitValue = process.waitFor()
            if (exitValue != 0) {
                println("exit with $exitValue")
                result.add("exit with $exitValue")
                return result
            }
    
            process.inputStream.bufferedReader().lines().forEach {
                println(it)
                result.add(it)
            }
            return result
        }
    
    
    
    

    我们使用

    val numbers: MutableList<Int> = mutableListOf(1, 2, 3)
    

    创建一个初始化元素1,2,3的元素类型为Int的MutableList<Int>可变List。

    使用

    val result = mutableListOf<String>()
    

    创建一个空的MutableList<String>元素类型为String的可变List。

    Kotlin 没有专门的语法结构创建 list 或 set。 要用标准库的方法,如
    listOf()mutableListOf()setOf()mutableSetOf()
    在非性能关键代码中创建 map 可以用一个简单的惯用法来完成:mapOf(a to b, c to d)

    注意上面的 readOnlyView 变量(译者注:与对应可变集合变量 numbers)指向相同的底层 list 并会随之改变。 如果一个 list 只存在只读引用,我们可以考虑该集合完全不可变。创建一个这样的集合的一个简单方式如下:

    val items = listOf(1, 2, 3)
    

    目前 listOf 方法是使用 array list 实现的,但是未来可以利用它们知道自己不能变的事实,返回更节约内存的完全不可变的集合类型。

    注意这些类型是协变的。这意味着,你可以把一个 List<Rectangle> 赋值给 List<Shape> 假定 Rectangle 继承自 Shape。对于可变集合类型这是不允许的,因为这将导致运行时故障。

    有时你想给调用者返回一个集合在某个特定时间的一个快照, 一个保证不会变的:

    class Controller {
        private val _items = mutableListOf<String>()
        val items: List<String> get() = _items.toList()
    }
    

    这个 toList 扩展方法只是复制列表项,因此返回的 list 保证永远不会改变。

    List 和 set 有很多有用的扩展方法值得熟悉:

    val items = listOf(1, 2, 3, 4)
    items.first() == 1
    items.last() == 4
    items.filter { it % 2 == 0 }   // 返回 [2, 4]
    
    val rwList = mutableListOf(1, 2, 3)
    rwList.requireNoNulls()        // 返回 [1, 2, 3]
    if (rwList.none { it > 6 }) println("No items above 6")  // 输出“No items above 6”
    val item = rwList.firstOrNull()
    

    …… 以及所有你所期望的实用工具,例如 sort、zip、fold、reduce 等等。

    Map 遵循同样模式。它们可以容易地实例化和访问,像这样:

    val readWriteMap = hashMapOf("foo" to 1, "bar" to 2)
    println(readWriteMap["foo"])  // 输出“1”
    val snapshot: Map<String, Int> = HashMap(readWriteMap)
    

    小结

    本章示例代码:https://github.com/EasyKotlin/easykotlin

    参考资料

    1.http://kotlinlang.org/docs/reference/grammar.html

    相关文章

      网友评论

        本文标题:《Kotlin 程序设计》第四章 Kotlin 语法基础

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