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

前言

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` 分支, 因为我们已经覆盖了所有的可能情况
}
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
【社区内容提示】社区部分内容疑似由AI辅助生成,浏览时请结合常识与多方信息审慎甄别。
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

相关阅读更多精彩内容

友情链接更多精彩内容