【问题标题】:Is it possible to compose two sealed classes?是否可以组成两个密封类?
【发布时间】:2023-03-18 20:15:01
【问题描述】:

我有两个不同的 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
    }
    .....
  }
}

【问题讨论】:

    标签: kotlin sealed-class


    【解决方案1】:

    我想你是在问union type。已经有 long discussions 关于向 Kotlin 添加一个,但看起来不太可能很快发生。

    同时,你当然可以有一个显式的父类:

    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() 的好处在于它既可以用作文档,也可以用作编译不完整代码的方法!)

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

    【讨论】:

    • 你说得对,这解决了我在问题中提出的问题,遗憾的是它并没有解决我的现实生活问题(为了快速提出问题,我过于简化了)我真的有兴趣拥有基本密封类的多个变体。联合类型绝对是我想要的。我认为我可以通过扩展基本密封类来实现这一点,但在我使用的 Kotlin 版本中不允许这样做,因为它们并非都定义在同一个文件中。我的理解是,在较新的版本中,它可以在一个包中完成。
    【解决方案2】:

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

    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 中。

    【讨论】:

      【解决方案3】:

      只需创建一个超类:

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

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2020-02-16
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2012-05-19
        相关资源
        最近更新 更多