是否可以组成两个密封的类?

Is it possible to compose two sealed classes?

我有两个不同的 Kotlin 密封图像 类。

sealed class Fruit {
  object Apple : Fruit()
  object Orange : Fruit()
  object Banana : Fruit()
}

sealed class Vegetables {
  object Broccoli : Vegetable()
  object Carrot : Vegetable()
  object Spinach : Vegetable()
}

是否可以定义一个包含水果和蔬菜的类型?类似于 Produce = Fruit | Vegetable

这样你就可以写出类似

的东西
fun lookAtProduce(produce: Produce) {
  when (produce) {
    is Carrot -> {
      return "Orange"
    }
    is Apple -> {
      return "Red"
    }
    ....
  }
}

fun putItInSalad(vegetable: Vegetable) {
  when (vegetable) {
    is Spinach -> {
      return true
    }
    is Carrot -> {
      return false
    }
    .....
  }
}

创建一个超级class:

sealed class Produce
sealed class Fruit : Produce()
sealed class Vegetable : Produce()

我想你问的是 union type.  There have been long discussions 关于向 Kotlin 添加一个,但它看起来不太可能很快发生。

同时,您当然可以有明确的父级 class:

sealed class Produce

接下来的工作与您预期的差不多:

sealed class Fruit : Produce() {
    object Apple : Fruit()
    object Orange : Fruit()
    object Banana : Fruit()
}

sealed class Vegetable : Produce() {
    object Broccoli : Vegetable()
    object Carrot : Vegetable()
    object Spinach : Vegetable()
}

fun lookAtProduce(produce: Produce) =
    when (produce) {
        is Vegetable.Carrot ->  "Orange"
        is Fruit.Apple ->  "Red"
        else -> TODO()
    }
}

fun putItInSalad(vegetable: Vegetable) =
    when (vegetable) {
        is Vegetable.Spinach -> true
        is Vegetable.Carrot -> false
        else -> TODO()
    }
}

(你必须限定 Carrot 等,除非你为它们添加静态导入。)

TODO() 的好处在于它既可以作为文档,也可以作为一种获取不完整代码进行编译的方法!)

当然,这要求您可以访问要组合的两种类型,因此您可以添加公共父级 class。如果你不能这样做,一个更冗长的选择是使用 Either class(参见 here)。这将需要明确包装和打开产品,但在这种情况下可能是您可以获得的最接近的产品。

您无法创建联合类型,但您始终可以使用其他密封类型来模拟它。

sealed class Produce {
  class FruitProduce(val fruit: Fruit): Produce()
  class VegetableProduce(val vegetable: Vegetable): Produce()
}

...然后写

fun color(produce: Produce): String {
  return when (produce) {
    is Fruit -> when (produce.fruit) {
      is Orange -> "Orange"
      ...
    }
    is Vegetable -> when (produce.vegetable) {
      is Broccoli -> "Green"
      ...
    }
  }
}

今天没有比这更好的了:您需要将 fruitvegetable 对象包装在 FruitProduceVegetableProduce.