如何在Kotlin序列化时将Float类型speed字段保留三位小数?
解决方案
Kotlinx Serialization 本身没有提供直接的格式化注解来控制浮点数字的小数位数,要实现speed字段保留三位小数、distance字段保持原样的需求,你需要自定义序列化器,并通过@Serializable(with = ...)注解指定给speed字段。
步骤1:自定义浮点数字序列化器
创建一个专门处理三位小数格式化的序列化器,同时兼容可空类型:
import kotlinx.serialization.KSerializer import kotlinx.serialization.descriptors.PrimitiveKind import kotlinx.serialization.descriptors.PrimitiveSerialDescriptor import kotlinx.serialization.descriptors.SerialDescriptor import kotlinx.serialization.encoding.Decoder import kotlinx.serialization.encoding.Encoder object ThreeDecimalsFloatSerializer : KSerializer<Float?> { override val descriptor: SerialDescriptor = PrimitiveSerialDescriptor("ThreeDecimalsFloat", PrimitiveKind.FLOAT) override fun serialize(encoder: Encoder, value: Float?) { // 将浮点值四舍五入到三位小数 val roundedValue = value?.let { Math.round(it * 1000) / 1000.0F } ?: 0F encoder.encodeFloat(roundedValue) } override fun deserialize(decoder: Decoder): Float? { // 反序列化保持默认逻辑,直接解析浮点值 return decoder.decodeNullableFloat() } }
如果需要在JSON中把speed显示为带三位小数的字符串(比如"speed": "51.130"),可以修改序列化器的serialize方法:
override fun serialize(encoder: Encoder, value: Float?) { val formattedString = value?.let { String.format("%.3f", it) } ?: "0.000" encoder.encodeString(formattedString) }
步骤2:给speed字段绑定自定义序列化器
修改Event数据类,在speed字段上添加@Serializable(with = ...)注解:
import kotlinx.serialization.SerialName import kotlinx.serialization.Serializable import kotlinx.serialization.json.JsonElement @Serializable data class Event( @SerialName("name") val name: String? = "", @SerialName("speed") @Serializable(with = ThreeDecimalsFloatSerializer::class) val speed: Float? = 0F, @SerialName("distance") val distance: Float? = 0F, )
步骤3:测试序列化效果
使用你原来的序列化代码测试:
fun main() { val event = Event(speed = 51.129789f, distance = 123.456789f) val json = Json { encodeDefaults = true } val jsonString = json.encodeToString(event) println(jsonString) }
输出示例(数值型格式化):
{"name":"","speed":51.13,"distance":123.456787}
如果用字符串型格式化,输出会是:
{"name":"","speed":"51.130","distance":123.456787}
关键说明
- 自定义序列化器可以精准控制单个字段的序列化逻辑,不会影响其他字段(比如
distance保持默认序列化行为)。 - 四舍五入逻辑通过
Math.round(it * 1000) / 1000.0F实现,确保保留三位小数。
内容的提问来源于stack exchange,提问作者user1443721
相关产品推荐
相关产品推荐

