gpt4 book ai didi

enums - 使用关联类型时密封类与枚举

转载 作者:IT老高 更新时间:2023-10-28 13:34:00 24 4
gpt4 key购买 nike

我想基于 Int 创建一个颜色对象.我可以使用 sealed class 获得相同的结果和 enum并且想知道一个是否比另一个更好。

使用 sealed class :

sealed class SealedColor(val value: Int) {
class Red : SealedColor(0)
class Green : SealedColor(1)
class Blue : SealedColor(2)

companion object {
val map = hashMapOf(
0 to Red(),
1 to Green(),
2 to Blue()
)
}
}

val sealedColor: SealedColor = SealedColor.map[0]!!
when (sealedColor) {
is SealedColor.Red -> print("Red value ${sealedColor.value}")
is SealedColor.Green -> print("Green value ${sealedColor.value}")
is SealedColor.Blue -> print("Blue value ${sealedColor.value}")
}

使用 enum :
enum class EnumColor(val value: Int) {
Red(0),
Green(1),
Blue(2);

companion object {
fun valueOf(value: Int): EnumColor {
return EnumColor
.values()
.firstOrNull { it.value == value }
?: throw NotFoundException("Could not find EnumColor with value: $value")
}
}
}

val enumColor: EnumColor = EnumColor.valueOf(0)
when (enumColor) {
EnumColor.Red -> print("Red value ${enumColor.value}")
EnumColor.Green -> print("Green value ${enumColor.value}")
EnumColor.Blue -> print("Blue value ${enumColor.value}")
}

它们在性能方面是否相同?有没有更好的 kotlin 方法来达到相同的结果?

最佳答案

让我们通过对比示例在各个方面讨论枚举和密封类之间的区别。这将帮助您根据您的用例选择一个。

特性
枚举
在枚举类中,每个枚举值不能有自己的唯一属性。您被迫为每个枚举值拥有相同的属性:

enum class DeliveryStatus(val trackingId: String?) {
PREPARING(null),
DISPATCHED("27211"),
DELIVERED("27211"),
}
这里我们需要 trackingId仅适用于 DISPATCHEDDELIVERED , PREPARING被迫有一个 null值(value)。
密封类
在密封类的情况下,我们可以为每个子类型设置不同的属性:
sealed class DeliveryStatus
class Preparing() : DeliveryStatus()
class Dispatched(val trackingId: String) : DeliveryStatus()
class Delivered(val trackingId: String, val receiversName: String) : DeliveryStatus()
在这里,每个子类型都有不同的属性。 Preparing我们的用例不需要属性,因此我们可以灵活地不指定任何与强制 null 不同的属性。枚举中的值。 Dispatched拥有一处房产,而 Delivered有两个属性。
考虑示例 Color(val value: Int)在问题中,你有一个共同的 value: Int属性用于所有常量,并且由于您不需要为不同的常量使用不同的属性,因此在这种情况下应该使用枚举。

职能
枚举
枚举可以具有抽象函数以及常规函数。但是和属性一样,每个枚举值也必须具有相同的功能:
enum class DeliveryStatus {
PREPARING {
override fun cancelOrder() = println("Cancelled successfully")
},
DISPATCHED {
override fun cancelOrder() = println("Delivery rejected")
},
DELIVERED {
override fun cancelOrder() = println("Return initiated")
};

abstract fun cancelOrder()
}
在这个例子中,我们有一个 abstract功能 cancelOrder()我们必须 override在每个枚举值中。这意味着,对于不同的枚举值,我们不能有不同的函数。
用法:
class DeliveryManager {
fun cancelOrder(status: DeliveryStatus) {
status.cancelOrder()
}
}
密封类
在密封类中,我们可以为不同的子类型使用不同的函数:
sealed class DeliveryStatus

class Preparing : DeliveryStatus() {
fun cancelOrder() = println("Cancelled successfully")
}

class Dispatched : DeliveryStatus() {
fun rejectDelivery() = println("Delivery rejected")
}

class Delivered : DeliveryStatus() {
fun returnItem() = println("Return initiated")
}
这里我们有不同的功能: cancelOrder()Preparing , rejectDelivery()DispatchedreturnItem()Delivered .这使意图更清晰并使代码更具可读性,我们也可以选择不使用该功能,以防万一。
用法:
class DeliveryManager {
fun cancelOrder(status: DeliveryStatus) = when(status) {
is Preparing -> status.cancelOrder()
is Dispatched -> status.rejectDelivery()
is Delivered -> status.returnItem()
}
}
如果我们想要所有子类型的通用函数,就像在枚举示例中一样,我们可以通过在密封类本身中定义它然后在子类型中覆盖它来在密封类中使用它:
sealed class DeliveryStatus {
abstract fun cancelOrder()
}
对所有类型都有一个通用函数的好处是我们不必使用 is 进行类型检查。运算符(operator)。我们可以简单地使用多态,如 DeliveryManager 所示。枚举示例类。

遗产
枚举
enum值是对象,它们不能被扩展:
class LocallyDispatched : DeliveryStatus.DISPATCHED { }    // Error
enum class隐含地是 final ,所以它不能被其他类扩展:
class FoodDeliveryStatus : DeliveryStatus() { }            // Error
枚举类不能扩展其他类,它们只能扩展接口(interface):
open class OrderStatus { }
interface Cancellable { }

enum class DeliveryStatus : OrderStatus() { } // Error
enum class DeliveryStatus : Cancellable { } // OK
密封类
由于密封类的子类型是类型,它们可以被扩展:
class LocallyDispatched : Dispatched() { }                 // OK
密封类本身当然可以扩展!:
class PaymentReceived : DeliveryStatus()                   // OK
密封类可以扩展其他类以及接口(interface):
open class OrderStatus { }
interface Cancellable { }

sealed class DeliveryStatus : OrderStatus() { } // OK
sealed class DeliveryStatus : Cancellable { } // OK

实例数
枚举
由于枚举值是对象而不是类型,我们不能创建它们的多个实例:
enum class DeliveryStatus(val trackingId: String?) {
PREPARING(null),
DISPATCHED("27211"),
DELIVERED("27211"),
}
在本例中, DISPATCHED是一个对象而不是一个类型,所以它只能作为一个实例存在,我们不能从它创建更多的实例:
// Single instance
val dispatched1 = DeliveryStatus.DISPATCHED // OK

// Another instance
val dispatched2 = DeliveryStatus.DISPATCHED("45234") // Error
密封类
密封类的子类型是类型,因此我们可以创建这些类型的多个实例。我们也可以使用 object 使类型只有一个实例。宣言:
sealed class DeliveryStatus
object Preparing : DeliveryStatus()
class Dispatched(val trackingId: String) : DeliveryStatus()
data class Delivered(val receiversName: String) : DeliveryStatus()
在这个例子中,我们可以创建 Dispatched 的多个实例。和 Delivered .请注意,我们利用了密封类的子类型作为单例的能力 object , 普通 classdata class . Preparing可以只有一个 object ,就像一个枚举值:
// Multiple Instances
val dispatched1 = Dispatched("27211") // OK
val dispatched2 = Dispatched("45234") // OK

// Single Instance
val preparing1 = Preparing // OK
val preparing2 = Preparing() // Error
还要注意,在上面的代码中, Dispatched 的每个实例 trackingId 可以有不同的值属性(property)。

可序列化和可比较
枚举
enum class在 Kotlin 中由抽象类 java.lang.Enum 隐式扩展.因此,所有枚举值自动具有 equals() 的实现。 , toString() , hashCode() , SerializableComparable .我们不必定义它们。
密封类
对于密封类,我们需要手动定义它们或使用 data class用于自动 equals() , toString()hashcode()然后实现 SerializableComparable手动。

表现
枚举
枚举不会被垃圾收集,它们会在您的应用程序的整个生命周期中保留在内存中。这可能是有利的,也可能是不利的。
垃圾收集过程是昂贵的。对象创建也是如此,我们不想一次又一次地创建相同的对象。因此,使用枚举,您可以节省垃圾收集和对象创建的成本。这是好处。
缺点是枚举即使在不使用时也会留在内存中,这会使内存一直被占用。
如果您的应用程序中有 100 到 200 个枚举,则无需担心所有这些。但是,当您拥有更多数量时,您可以根据事实来决定是否应该使用枚举,例如枚举的数量、它们是否会一直使用以及分配给 JVM 的内存量。
枚举值的比较在 when 中更快表达式因为在引擎盖下,它使用 tableswitch来比较对象。因此,对于问题中给出的示例,应该首选枚举,因为在这种情况下它们会更快。
在 Android 中,当启用优化时,Proguard 会将没有函数和属性的枚举转换为整数,因此您可以在编译时获得枚举的类型安全性,并在运行时获得整数的性能!
密封类
密封类只是普通类,唯一的异常(exception)是它们需要在同一个包和同一个编译单元中进行扩展。所以,他们的表现相当于普通类(class)。
密封类的子类型的对象像常规类的对象一样被垃圾收集。因此,您必须承担垃圾收集和对象创建的成本。
当您有低内存限制时,如果您需要数千个对象,您可以考虑使用密封类而不是枚举。因为垃圾收集器可以在对象不使用时释放内存。
如果您使用 object扩展密封类的声明,对象充当单例,它们不会像枚举一样被垃圾收集。
密封类的类型比较在 when 中比较慢表达式,因为在引擎盖下它使用 instanceof来比较类型。在这种情况下,枚举和密封类之间的速度差异很小。仅当您在循环中比较数千个常量时才重要。

就是这样!希望这将使您更容易选择一个。

关于enums - 使用关联类型时密封类与枚举,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/49169086/

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com