You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

KMP中Ktor反序列化Double值变为科学计数法问题求助

Ktor 3.1.0反序列化Decimal为Double时出现科学计数法的解决办法

在KMP项目中使用Ktor 3.1.0调用RESTful服务时,接口返回的十进制数据(例如"rdInitialInventoryCost":17496887874.95)反序列化为Double类型后,会自动以科学计数法形式呈现(如1.749688787495E10),即便数据长度不长也会出现这个问题。当前使用的Ktor配置如下:

val ktorModule: Module = module {
    factory {
        HttpClient {
            install(ContentNegotiation) {
                json(
                    Json {
                        ignoreUnknownKeys = true
                        prettyPrint = true
                        isLenient = true
                        coerceInputValues = true
                        encodeDefaults = true
                        allowStructuredMapKeys = true
                    }
                )
            }
            defaultRequest {
                url {
                    host = ENVIRONMENT.urlSession
                    protocol = URLProtocol.HTTPS
                }

            }
            install(Logging) {
                logger = Logger.DEFAULT
                level = LogLevel.ALL
            }
            install(HttpTimeout) {
                requestTimeoutMillis = REQUEST_TIMEOUT
                connectTimeoutMillis = CONNECT_TIMEOUT
                socketTimeoutMillis = SOCKET_TIMEOUT
            }
        }
    }
}

解决办法

  • 优先用BigDecimal存储高精度数值
    Double是二进制浮点数,不仅容易触发科学计数法,还可能带来精度丢失问题,尤其不适合财务类高精度数值。直接把数据类里的对应字段改成BigDecimal类型,Ktor的Json序列化器原生支持这个类型的反序列化:

    data class InventoryData(
        val rdInitialInventoryCost: BigDecimal
    )
    
  • 强制Json序列化器用常规格式输出
    如果必须保留Double类型,可以在Json配置里添加useScientificNumberFormat = false,强制序列化器以普通十进制格式输出数值:

    json(
        Json {
            ignoreUnknownKeys = true
            prettyPrint = true
            isLenient = true
            coerceInputValues = true
            encodeDefaults = true
            allowStructuredMapKeys = true
            useScientificNumberFormat = false // 新增配置
        }
    )
    

    注意:这种方法只是改变输出格式,Double的内部存储依然是二进制浮点数,精度问题还是存在,仅适合非高精度场景。

  • 格式化Double为字符串展示
    如果只是展示时需要常规格式,可以把Double值转成格式化后的字符串。JVM端可以用DecimalFormat,跨平台场景可以用第三方格式化库:

    // JVM端示例
    val formatter = DecimalFormat("#.##")
    formatter.isGroupingUsed = false
    val normalFormat = formatter.format(1.749688787495E10) // 得到17496887874.95
    

内容的提问来源于stack exchange,提问作者Juan Esteban Lopez

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.13 11:41:10