如何从枚举中继承?

huangapple go评论60阅读模式
英文:

How to inherit from enums?

问题

我有两个不同的枚举:

enum class As(val value: String) {
    A1("a1"),
    A2("a2"),
    A3("a3"),
    Unknown("null")
}

enum class Bs(val value: String) {
    B1("b1"),
    B2("b2"),
    Unknown("null")
}

由于两者都有一个共同的条目,我想要继承枚举:

enum class Upper(val value: String) {
    
    Unknown("null")
}

然后:

enum class As(val value: String): Upper(value) {
    A1("a1"),
    A2("a2"),
    A3("a3")
}

enum class Bs(val value: String): Upper(value) {
    B1("b1"),
    B2("b2")
}

此外,我想在一个函数中将 Upper 用作参数:

@Composable
fun aFunc(upper: Upper, ....) {
    when(upper){
        is As -> //..
        is Bs -> //..
        else -> //..
    }
}

不幸的是,我无法从枚举中继承。否则,我将不得不重载参数:

@Composable
fun aFunc(a: As, ....) {
    //..
}

@Composable
fun aFunc(b: Bs, ....) {
    //..
}

有没有什么聪明的解决方案?

英文:

I have two different enums:

enum class As(val value: String) {
    A1("a1"),
    A2("a2"),
    A3("a3"),
    Unknown("null")
}

and

enum class Bs(val value: String) {
    B1("b1"),
    B2("b2"),
    Unknown("null")
}

since both have a common entry, I would like to inherit enums:

enum class Upper(val value: String) {
    
    Unknown("null")
}

and then:

enum class As(val value: String): Upper(value) {
    A1("a1"),
    A2("a2"),
    A3("a3")
}

and

enum class Bs(val value: String): Upper(value) {
    B1("b1"),
    B2("b2")
}

Also I would like to use the Upper as a parameter in a function:

@Composable
fun aFunc(upper: Upper, ....) {
    when(upper){
        is As -> //..
        is Bs -> //..
        else //..
    }
}

Unfortunately I can not inherit from enums. Otherwise I would have to overload parameters:

@Composable
fun aFunc(a: As, ....) {
    //..
}

and

@Composable
fun aFunc(b: Bs, ....) {
    //..
}

Any smart solution here?

答案1

得分: 2

枚举类型的继承在Kotlin中不受支持(在Java中也不可能)。让我们看看这个例子:

enum class Coordinates { X, Y }
enum class Coordinates3D : Coordinates { Z }

val xd: Coordinates = ... // 这个赋值的可能取值是什么?X、Y还是Z?

那么,我们可以用什么来替代枚举类型呢?
是的!可以使用密封类 如何从枚举中继承?

sealed class S(val value: String) {
    object Unknown : S("null")
}

sealed class As(value: String) : S(value) {
    object A1 : As("a1")
    object A2 : As("a2")
    object A3 : As("a3")
}

sealed class Bs(value: String) : S(value) {
    object B1 : Bs("a1")
    object B2 : Bs("a2")
}

// 您可以对所有可能的类型进行详尽的分支处理。
fun example(s: S): String {
	return when(s) {
		// 必须定义S的所有可能情况(以及所有可能的子情况)
		S.Unknown -> "S.Unknown"
		As.A1 -> "As.a1"
		As.A2 -> "As.a2"
		As.A3 -> "As.a3"
		Bs.B1 -> "Bs.b1"
		Bs.B2 -> "Bs.b2"
	}
}

// 您也可以按“子类型族”进行匹配。
fun example2(s: S): String {
	return when(s) {
		S.Unknown -> "Unknown"
		is As -> "As"
		is Bs -> "Bs"
	}
}

请注意,以上是代码的翻译部分。如果您需要更多信息或有其他问题,请随时提出。

英文:

Enum inheritance is not supported in Kotlin (and in Java it's not possible too). Let's see this example:

enum class Coordinates { X, Y }
enum class Coordinates3D : Coordinates { Z }

val xd: Coordinates = ... // which is a limited set of this assigment? X, Y or Z too?

So, is there something we can replace enums with?
Yes! Sealed classes 如何从枚举中继承?

sealed class S(val value: String) {
    object Unknown : S("null")
}

sealed class As(value: String) : S(value) {
    object A1 : As("a1")
    object A2 : As("a2")
    object A3 : As("a3")
}

sealed class Bs(value: String) : S(value) {
    object B1 : Bs("a1")
    object B2 : Bs("a2")
}

// You can use exhaustive branching for all possible types.
fun example(s: S): String {
	return when(s) {
		// must define all possible cases of S (and all possible subcases)
		S.Unknown -> "S.Unknown"
		As.A1 -> "As.a1"
		As.A2 -> "As.a2"
		As.A3 -> "As.a3"
		Bs.B1 -> "Bs.b1"
		Bs.B2 -> "Bs.b2"
	}
}

// You can match by "subtype family" too.
fun example2(s: S): String {
	return when(s) {
		S.Unknown -> "Unknown"
		is As -> "As"
		is Bs -> "Bs"
	}
}

答案2

得分: 0

一种可能性是消除AsBs的枚举,创建一个代表子类型(AB)的新枚举。

enum class SubType { A, B }

然后,您在枚举中指定子类型作为属性。

enum class Upper(val value: String, val subType: SubType? = null) {
    A1("a1", SubType.A),
    A2("a2", SubType.A),
    A3("a3", SubType.A),
    B1("b1", SubType.B),
    B2("b2", SubType.B),
    Unknown("null")
}

在您的函数中,您检查subType属性而不是其类型。

fun aFunc(upper: Upper) {
    when(upper.subType){
        SubType.A -> //..
        SubType.B -> //..
        null -> //..
    }
}

奖励

然而,现在内置的静态方法values()将返回所有枚举值,而不仅仅是AsBs。因此,我们可以添加一个新方法:

enum class Upper(val value: String, val subType: SubType? = null) {
    A1("a1", SubType.A),
    A2("a2", SubType.A),
    A3("a3", SubType.A),
    B1("b1", SubType.B),
    B2("b2", SubType.B),
    Unknown("null");

    companion object {
        fun valuesOf(subType: SubType?): List<Upper> =
            values().filter { it.subType == subType }
    }
}

其他想法

还有一个重要的考虑因素是,是否真正需要继承来解决您的问题。有点重复通常比创建错误的抽象更好,继承通常是一个潜在的问题。我建议查看Code Aesthetic的“继承的缺陷”

无关的,但值得一提的是,组合函数的命名约定是使用PascalCase,而不是camelCase。

英文:

One possibility is to eliminate enums As and Bs, and create a new enum that represents the sub type (either A or B).

enum class SubType { A, B }

Then you specify the subtype as a property in the enum.

enum class Upper(val value: String, val subType: SubType? = null) {
    A1(&quot;a1&quot;, SubType.A),
    A2(&quot;a2&quot;, SubType.A),
    A3(&quot;a3&quot;, SubType.A),
    B1(&quot;b1&quot;, SubType.B),
    B2(&quot;b2&quot;, SubType.B),
    Unknown(&quot;null&quot;)
}

In your function, you check the subType property rather than its type.

fun aFunc(upper: Upper) {
    when(upper.subType){
        SubType.A -&gt; //..
        SubType.B -&gt; //..
        null -&gt; //..
    }
}

Bonus

However, now the built-in static method values() will return all enum values, rather than just As or Bs. So, we can add a new method:

enum class Upper(val value: String, val subType: SubType? = null) {
    A1(&quot;a1&quot;, SubType.A),
    A2(&quot;a2&quot;, SubType.A),
    A3(&quot;a3&quot;, SubType.A),
    B1(&quot;b1&quot;, SubType.B),
    B2(&quot;b2&quot;, SubType.B),
    Unknown(&quot;null&quot;);

    companion object {
        fun valuesOf(subType: SubType?): List&lt;Upper&gt; =
            values().filter { it.subType == subType }
    }
}

Other Thoughts

It's also important to consider if inheritance is truly necessary for your problem. A little bit of duplication is better than making the wrong abstraction, and inheritance can often be a huge footgun. I recommend checking out Code Aesthetic's The Flaws of Inheritance

Unrelated, but worth mentioning - the naming convention for composable functions is to use PascalCase, not camelCase.

huangapple
  • 本文由 发表于 2023年2月23日 21:28:23
  • 转载请务必保留本文链接:https://go.coder-hub.com/75545507.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定