【问题标题】:Force all Kotlin Sealed classes to have a standard entry?强制所有 Kotlin 密封类都有标准条目?
【发布时间】:2019-11-15 14:30:46
【问题描述】:

我正在调查 Kotlin 密封类。

我希望强制我的所有密封类具有 NO_OP 的标准值。

例如:-

密封类 1

sealed class Operation {
    object NO_OP: Operation()
    class Add(val value: Int) : Operation()
    class Substract(val value: Int) : Operation()
    class Multiply(val value: Int) : Operation()
    class Divide(val value: Int) : Operation()
}

2 级密封

sealed class ScreenState {
    object NO_OP: ScreenState()
    class Error : ScreenState()
    class Loading : ScreenState()
    data class Data(val someData: SomeData) : ScreenState()
}

我可以采取任何方法来强制单独文件中的所有密封类 总是指定 NO_OP 值?

【问题讨论】:

    标签: kotlin sealed-class


    【解决方案1】:

    如果您想将其强制覆盖为某些密封类的字段:

    sealed class ScreenState {
        abstract val NO_OP: ScreenState
    
        class Error : ScreenState() {
           override val NO_OP: ScreenState
              get() = TODO("Your implementation")
        }
    }
    

    如果您需要类似界面的东西:

    sealed class ScreenState : NoOp<ScreenState> {
        override val NO_OP: ScreenState = Error()
    
        class Error : ScreenState()
    }
    
    interface NoOp<T> {
       val NO_OP: T
    }
    

    【讨论】:

      【解决方案2】:

      这在目前的语言中似乎是不可能的。 但是,我们可以将 NO_OP 从密封层次结构中移出,并使用箭头库中的 Coproduct 来定义临时密封层次结构:

      import arrow.generic.coproduct2.Coproduct2
      
      sealed class Operation {
          class Add(val value: Int) : Operation()
          class Substract(val value: Int) : Operation()
          class Multiply(val value: Int) : Operation()
          class Divide(val value: Int) : Operation()
      }
      
      object NO_OP
      
      typealias Operations = Coproduct2<NO_OP, Operation>
      

      或者我们可以修复Coproduct中的类型参数之一,并且有:

      typealias SomeThingWithNoOp<T> = Coproduct<NO_OP, T>
      

      但是,这并不理想,因为它使层次结构嵌套。顶层是Coproduct,嵌套层是自定义层次结构。 这可能会在不久的将来通过 Arrow-Meta 的联合类型插件来解决。


      查看问题的另一种方法是将NO_OP 视为标记值。因此我们可以将NO_OP 编码为null 或None(来自箭头选项):

      sealed class Operation {
          class Add(val value: Int) : Operation()
          class Substract(val value: Int) : Operation()
          class Multiply(val value: Int) : Operation()
          class Divide(val value: Int) : Operation()
      }
      
      typealias Operations = Operation?
      
      import arrow.core.Option
      
      sealed class Operation {
          class Add(val value: Int) : Operation()
          class Substract(val value: Int) : Operation()
          class Multiply(val value: Int) : Operation()
          class Divide(val value: Int) : Operation()
      }
      
      typealias Operations = Option<Operation>
      

      根据我的经验,将其编码为可空可能更容易使用,因为 Kotlin 具有内置的可空类型支持。虽然将其编码为OptionCoproduct 或在每个密封层次结构中定义NO_OP 会使其更加明显(尤其是通过在密封层次结构中使用CoproductNO_OP)。


      参考:

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2021-11-05
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多