Kotlinx.serialization 深度解析:值类的序列化处理

Kotlinx.serialization 深度解析:值类的序列化处理

kotlinx.serialization Kotlin multiplatform / multi-format serialization kotlinx.serialization 项目地址: https://gitcode.com/gh_mirrors/ko/kotlinx.serialization

什么是值类?

值类(Value Class)是 Kotlin 中一种特殊的类,通过 @JvmInline 注解标记,主要用于包装单个值而不引入运行时开销。值类在可能的情况下会直接存储为其底层类型(不需要装箱操作),这为性能优化提供了可能。

值类的序列化基础

在 kotlinx.serialization 中处理值类非常简单,只需为值类添加 @Serializable 注解:

@Serializable
@JvmInline
value class Color(val rgb: Int)

当值类被序列化时,框架会直接使用其底层类型,不会包含值类本身的类型信息。例如:

@Serializable
data class NamedColor(val color: Color, val name: String)

fun main() {
    println(Json.encodeToString(NamedColor(Color(0), "black")))
}

输出结果为:

{"color": 0, "name": "black"}

可以看到,输出中只包含底层 Int 值,没有 Color 类型信息。

集合中的值类处理

即使值类被用作泛型类型参数(此时会触发实际分配),序列化行为依然保持一致:

@Serializable
class Palette(val colors: List<Color>)

fun main() {
    println(Json.encodeToString(Palette(listOf(Color(0), Color(255), Color(128)))))
}

输出:

{"colors":[0, 255, 128]}

JSON 对无符号类型的特殊支持

Kotlin 标准库通过值类提供了无符号类型:UByteUShortUIntULong。kotlinx.serialization 的 JSON 格式为这些类型提供了内置支持,将它们序列化为无符号形式的字符串表示。

@Serializable
class Counter(val counted: UByte, val description: String)

fun main() {
    val counted = 239.toUByte()
    println(Json.encodeToString(Counter(counted, "tries")))
}

输出:

{"counted":239,"description":"tries"}

注意:目前只有 JSON 格式支持无符号类型的这种特殊表示,其他格式如 ProtoBuf 和 CBOR 会使用底层的有符号表示。

为值类编写自定义序列化器

当需要为包含值类的类编写自定义序列化器时,需要注意避免值类的装箱操作。常规的 encodeSerializableElement 会导致值类被装箱,应该改用 encodeInlineElement

override fun serialize(encoder: Encoder, value: NamedColor) {
    encoder.encodeStructure(descriptor) {
        encodeInlineElement(descriptor, 0).encodeInt(value.color)
        encodeStringElement(descriptor, 1, value.name)
    }
}

encodeInlineElement 返回一个 Encoder,可以直接对未装箱的值进行操作。

将类表示为原始值

如果类需要表示为原始值(而非结构),可以使用 encodeInline 方法。例如,将一个包含 Int 的类表示为 JSON 中的无符号整数:

@Serializable(UIDSerializer::class)
class UID(val uid: Int)

object UIDSerializer: KSerializer<UID> {
    override val descriptor = UInt.serializer().descriptor
    
    override fun serialize(encoder: Encoder, value: UID) {
        encoder.encodeInline(descriptor).encodeInt(value.uid)
    }
    
    override fun deserialize(decoder: Decoder): UID {
        return UID(decoder.decodeInline(descriptor).decodeInt())
    }
}

这里的关键是使用了 UInt 的描述符,使得 JSON 格式器将后续的 encodeInt 调用处理为无符号整数。

重要注意事项

  1. 为值类编写自定义序列化器时,应该只使用 encodeInline 相关方法
  2. 值类序列化器的调用可能会被优化替换为 encodeInlineElement 调用
  3. 相同的描述符应该总是产生相同的 Encoder 行为
  4. 避免在值类序列化器中嵌入可能被优化掉的逻辑

通过合理利用值类的序列化特性,可以在保持类型安全的同时获得最佳的性能表现。

kotlinx.serialization Kotlin multiplatform / multi-format serialization kotlinx.serialization 项目地址: https://gitcode.com/gh_mirrors/ko/kotlinx.serialization

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

秋玥多

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值