考虑一下这个极其简化的代码(在https://pl.kotl.in/bb2Irv8dD上可用):

sealed class Person {
    data class A(val i: Int) :
        Person()
}

fun main() {
    val a = Person.A(i = 0)
    val b = Person.A(i = 1)
    
    // Compiles
    when (a) { 
        is Person.A -> print("I have access to {$a.i}")
    }
    
    // Does not compile :(
    when (a to b) { 
        is Person.A to is Person.A -> print("I have access to {$a.i} and b {$b.i}")
    }
}

为什么(a to b)代码不起作用?它适用于1个变量,我希望我可以在两个类上匹配,并获得两个内部值.

错误是:

不兼容的类型:Person.A和Pair<Person.A,Person.A>预期 "->"需要元素不兼容的类型:Person.A和 Pair<Person.A,Person.A>

推荐答案

除了不支持的语法(您只能对when分支中的一件事使用is),使用to实际上就是创建了Pair类的一个实例.

Pair对其两个变量的类型使用泛型,因此该类型信息在运行时由于type erasure而丢失.

所以,尽管你们can人这样做:

when (a to b) { 
    is Pair<Person.A, Person.A> -> print("I have access to {$a.i} and b {$b.i}")
}

只有当ab都是局部变量,其类型是在本地声明的,以便在编译时知道这对的泛型类型时,才允许这样做.但这使得它几乎毫无用处,因为如果ab是编译时类型已知的局部变量,则只需将上面的变量替换为真或假即可.

要在一般情况下执行此类操作,您必须创建要使用的局部变量:

val aIsTypeA = a is Person.A
val bIsTypeA = b is Person.A
when (aIsTypeA to bIsTypeA) {
    true to true -> //...
    //...
}

或者使用不带主语的when,并在每个分支上添加完整条件:

when {
    a is Person.A && b is Person.A -> //...
    //...
}

Kotlin相关问答推荐

Fleet无法从构建文件自动重新加载更改错误'

在Kotlin Jetpack中重用下拉菜单

我可以检测一个函数是否在Kotlin中被递归调用(即,重入)吗?

Kotlin多平台(KMP)保存到文件不能在iOS上保存

为什么可组合对象看似无状态(唯一传递的参数是函数,而不是状态),但会进行重组

Webpack 配置未应用于 kotlin 多平台react 项目

Kotlin:我可以将函数分配给 main 的伴随对象中的变量吗?

Kotlin 中的as Long和.toLong()有什么区别?

在 kotlin 中模拟伴随对象函数

找不到引用的类 kotlin.internal.annotations.AvoidUninitializedObjectCopyingCheck

如何在 kotlin @Parcelize 中使用 null

Android 导航组件 - 向上导航打开相同的片段

Kotlin 协程中的 Dispatchers.Main 和 Dispatchers.Default 有什么区别?

IntelliJ 不会根据 ktlint 的期望对 Kotlin 导入进行排序

找不到 androidsdk.modules

在 Spring Framework 5.1 中注册具有相同名称的测试 bean

Dagger2 Qualifier 不适用于 Kotlin?

Kotlin 中的内联构造函数是什么?

如何捕获传递给模拟函数的参数并返回它?

Kotlin-将UTC转换为当地时间