英文:
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
一种可能性是消除As
和Bs
的枚举,创建一个代表子类型(A
或B
)的新枚举。
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()
将返回所有枚举值,而不仅仅是As
或Bs
。因此,我们可以添加一个新方法:
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("a1", SubType.A),
A2("a2", SubType.A),
A3("a3", SubType.A),
B1("b1", SubType.B),
B2("b2", SubType.B),
Unknown("null")
}
In your function, you check the subType
property rather than its type.
fun aFunc(upper: Upper) {
when(upper.subType){
SubType.A -> //..
SubType.B -> //..
null -> //..
}
}
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("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 }
}
}
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.
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论