美文网首页
Kotlin for android学习四:数据类与封闭类

Kotlin for android学习四:数据类与封闭类

作者: crossroads | 来源:发表于2017-10-19 11:52 被阅读21次

    前言

    kotlin官网 (中文版)和kotlin教程学习教程的笔记。

    一、数据类

    1. 数据类是仅仅包含状态而没有任何可执行的操作,通过data关键字标记:
    data class User(val name:String,val age:Int)
    

    然后,编译器会根据主构造器中声明的全部属性,自动推断产生以下成员函数:

    • equals()/hashCode()函数对
    • toString()函数,输出格式为 User(name=**,age=**)
    • componentN()函数群,这些函数与类的属性对应, 函数名中的数字 1 到 N, 与属性的声明顺序一致(详细见下文)
    • copy()函数(详细见下文)

    如果上述任意一个成员函数在类定义体中有明确的定义, 或者从基类继承得到, 那么这个成员函数不会自动生成.

    1. 为了保证自动生成的代码的行为一致, 并且有意义, 数据类必须满足以下所有要求:
    • 主构造器至少要有一个参数
    • 主构造器的所有参数必须标记为val或var
    • 数据类不能是抽象类、open类、封闭类、内部类
    • 数据类不能继承自任何其他类(但可以实现接口)

    在 JVM 上, 如果自动生成的类需要拥有一个无参数的构造器, 那么需要为所有的属性指定默认值
    data class User(val name: String = "", val age: Int = 0)

    二、对象复制

    我们经常会需要复制一个对象,然后修改它的一部分属性,但保持其他属性不变,这就是自动生成的copy()函数所需要实现的功能。
    对于前面示例中的 User 类, 自动生成的 copy() 函数的实现将会是下面这
    样:

    fun copy(name: String = this.name, age: Int = this.age) = User(name, age)
    

    copy()函数的使用方式

    data class User(var name:String="jack",val age: Int)
    
    var jack = User(age = 18)
    var oldJack = jack.copy(age = 81)
    

    三、数据类中成员数据的解构

    编译器会为数据类生成组件函数(Component function),有了这些函数,就可以在解构声明中使用数据类

    var jack = User(age = 18)
    val(name,age)=jack
    println("$name,$age")//输出jack,18
    

    四、标准库中的数据类

    Kotlin 的标准库提供了 Pair 和 Triple 类可供使用.

     val (rank, money)  = Pair(1, "10000")
     println(" $rank -> $money")//输出 1 -> 10000
    

    但是, 大多数情况下, 使用有具体名称的数据了是一种更好的设计方式, 因为, 数据类可以为属性指定有含义的名称, 因此可以增加代码的可读性.

    小知识补充

    解构声明(Destructuring Declaration)
    1. 将一个对象解构为多个变量,例如val(name,age)=user 这种语法成为解构声明。
    2. 我们已知一个解构声明回一次性创建多个变量,我们声明了两个变量name和age,并可以单独使用这两个变量println(age)println(name)
    3. 解构声明在编译时被分解为以下代码
    val name=user.component1()
    val age=user.component2()
    

    当然, 还可以存在component3() 和 component4() 等等.

    1. 任何东西都可以作为解构声明右侧的被解构值, 只要可以对它调用足够数量的组件函数(component function).
    2. componentN() 函数需要标记为 operator , 才可以在解构声明中使用.
      举个例子,从一个函数返回两个值:
    fun c(age: Int): User {
       return User(age = age)
    }
    // 由于数据类会自动声明 componentN() 函数, 因此可以在这里使用解构声明.
    val (name, age) = c(18)
    println(name)
    println(age)
    

    但是有时候,我只想要解构部分属性怎么办?

     class User(val name: String, val age: Int) {
        operator fun component1(): Any {
            return age
        }
    }
    var user = User("name", 10)
    val (comp1) = user
    println(comp1)//输出10
    

    解构声明与Map

    operator fun <K, V> Map<K, V>.iterator(): Iterator<Map.Entry<K, V>> = entrySet().iterator() 
    operator fun <K, V> Map.Entry<K, V>.component1() = getKey()
    operator fun <K, V> Map.Entry<K, V>.component2() = getValue()
    
    for ((key, value) in map) {
    // 使用 key 和 value 执行某种操作
    }
    

    五、封闭类(Sealed class)

    1. 封闭类可以限制一个值只允许是某些指定的类型之一,而不允许是其他的类型。
    2. 要声明一个封闭类,需要将 sealed 修饰符放在类名之前.封闭类可以有子类,但所有的子类声明都必须嵌套在封闭类的声明部分之内.但是,从封闭类的子类再继承的子类(间接继承者)可以放在任何地方, 不必在封闭类的声明部分之内.
    sealed class Expr {
    class Const(val number: Double) : Expr() 
    class Sum(val e1: Expr, val e2: Expr) : Expr()
     object NotANumber : Expr()
    }
    
    fun eval(expr: Expr): Double = when(expr) {
    is Expr.Const -> expr.number
    is Expr.Sum -> eval(expr.e1) + eval(expr.e2)
    Expr.NotANumber -> Double.NaN
    // 不需要 `else` 分支, 因为我们已经覆盖了所有的可能情况
    }
    

    相关文章

      网友评论

          本文标题:Kotlin for android学习四:数据类与封闭类

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