Destructuring declarations
Destructuring declarations

Destructuring declarations

提供方: JetBrains 学院

有时,将一个对象解构为多个变量会很方便。例如,为了更好地操作对象,或者为了使代码更简洁。在本主题中,我们将了解如何实现这一点。

基本解构

假设你有一个 User ,用于存储用户信息。它有诸如 String name 、Int age 和 Boolean isAdmin 之类的字段。

data class User(val name: String, val age: Int, val isAdmin: Boolean)

val anonym = User("Anonym", 999, false)

好了,这就是我们需要的全部内容!现在我们可以将所有变量从类中分离出来,并将它们作为单独的对象进行操作:

val (userName, userAge, isAdmin) = anonym
println(userName)  // prints Anonym
println(userAge)   // prints 999
println(isAdmin)   // prints false

此功能称为 。 解构声明可以一次性创建多个变量。我们声明了三个新变量: userName 、 userAge 和 isAdmin 。

解构声明使用 componentN() 运算符,它返回类中的第 n 个元素。上面的代码编译成以下代码:

val userName = anonym.component1()
val userAge = anonym.component2()
val isAdmin = anonym.component3()

无需数据类的解构

即使不使用数据类,也可以使用解构赋值。我们只需要手动定义一个 componentN 运算符 。运算符类似于函数,但使用特殊的符号来对操作数/值执行操作。例如, + 是一个执行加法的运算符。就是这样!你可以把它想象成一个函数。现在让我们尝试重写一些用于解构赋值的运算符:

class User(val name: String, val age: Int, val isAdmin: Boolean){
    operator fun component1(): String = name
    operator fun component2(): Int = age
    operator fun component3(): Boolean = isAdmin
}

// now we can use default destructuring syntax
fun checkIsAdmin(suspiciousUser: User) {
    // destructuring
    val (name, age, isAdmin) = suspiciousUser

    if (isAdmin)
        println("Have a nice day!")
    else
        println("Sorry, you should not be here.")
}

componentN 函数的工作原理依赖于每个类变量的位置。但这存在问题,因为类本身并非基于位置关系,因此很容易出错。

请注意,我们不能在数据类中重写 componentN 运算符,因为 Kotlin 会自动处理:

// Error: Conflicting overloads: public final operator fun component1(): String defined in StoreClass
data class StoreClass(val info: String) {
    operator fun component1() = info
}

使用列表和循环进行解构

解构声明也适用于列表和循环,因为 List 是一个实现了 componentN 运算符的类。现在,让我们提取前 3 个元素:

fun processList(customerInfo: MutableList<String>) {
    if (customerInfo.size < 3) return
    val (firstName, lastName, city) = customerInfo
    showCustomerName(firstName, lastName)
    findPopularSellersInCity(city)
}

如果列表元素超过 3 个,剩余的元素将不会被处理,程序会继续执行。同样地,如果列表元素少于 3 个,则会发生错误,程序会崩溃。为了避免这种情况,我们添加了一个 if 判断语句。

请注意,我们可以从一个包含超过 N 个元素的列表或类中获取前 N 个元素。这在某些情况下可能很有用。

for 循环中的解构也涉及到 componentN 运算符。现在,让我们把公司所有非管理员用户的数据发送给分析师:

fun processAnalytics(usersData: MutableList<User>) {
    for ((name, age, isAdmin) in usersData) {
        if (!isAdmin)
            sendAnalyticsToCompany(name, age)
    }
}

这样, MutableList<User> 中的每个元素都将被解构。

变量下划线

当我们开始使用解构声明时,Kotlin 编译器可能会警告我们解构声明中存在未使用的变量。IDE 的默认解决方案是将未使用的变量重命名为“_”( 下划线 ),但这存在一些缺点。例如,我们尝试从其他地方复制粘贴一些代码:

val usersData = mutableListOf<User>()
for ((_, _, isAdmin) in usersData) {
    // /~
}

看起来很眼熟,对吧?在上面的例子中, componentN 运算符跳过了 name 和 age 属性,因此它们不能在循环中使用。

另一个实用功能是 尾随逗号 。你可以在参数列表末尾添加逗号,它就能正常工作。这非常方便,因为你可以复制粘贴额外的参数而无需添加逗号。

val usersData = mutableListOf<User>()
for ((name, age, ) in usersData) {
    // /~
}

结论

解构声明是一种便捷的特性,它允许以类似元组的方式声明新变量,从而生成更简洁易读的代码。然而,它的位置机制与类变量的关联性本质上不同,这可能会导致错误。

200 名学员喜欢这篇理论文章, 8 名学员不喜欢。 你觉得呢?

报告拼写错误

相关条目

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注