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

如何按需将PostgreSQL的Numeric类型解析为Rust原生类型

问题根因

你遇到的类型转换错误和feature配置不全、类型映射规则理解偏差直接相关:

  • Rust的i64/u64等原生整数类型,在postgres crate中仅默认映射Postgres的BIGINT/INT8类型,不会自动匹配NUMERIC类型。因为NUMERIC是任意精度数值类型,可存储小数、也可存储远超原生整数范围的值,自动隐式转换存在溢出、精度丢失风险,官方没有做默认适配。
  • 你看到文档中标注的整数类型转换支持,对应的就是Postgres原生整数类型,不是NUMERIC,所以直接用i64接NUMERIC字段必然报错。
  • 自定义包装类型实现FromSql/ToSql不是必须方案,官方已经提供了现成的适配支持。
可用解决方案

方案1:开启官方feature使用精确数值类型(生产环境推荐,尤其适合价格场景)

你当前只开了with-chrono-0_4时间类型适配,缺少NUMERIC类型对应的适配feature,直接补上即可,不需要自己写转换逻辑:

  1. 调整Cargo.toml依赖,开启rust_decimal适配feature(精确小数场景首选,无浮点精度误差):
    postgres = {version = "0.19.3", features = ["with-chrono-0_4", "with-rust_decimal-1"]}
    rust_decimal = "1"
    
  2. 读取代码中替换对应字段类型即可:
    use chrono::{DateTime, Utc};
    use rust_decimal::Decimal;
    use postgres::Client;
    
    // ...
    for row in client.query("SELECT * FROM pricetable;", &[])? {
        let time: DateTime<Utc> = row.get(0);
        let price: Decimal = row.get(1);
        // 如果你确定字段存的是整数值,可安全转成i64使用
        let price_i64: i64 = price.try_into().expect("price value out of i64 range");
        println!("found datum: {} {} ", time, price);
    }
    

如果需要处理超大范围的数值,也可以换成开启with-bigdecimal-0_3feature,对应使用bigdecimal::BigDecimal类型接收即可。

方案2:SQL侧做类型强转(快速调试/临时使用)

如果确定表中price字段存储的全是i64范围内的整数、没有小数,可以直接在查询语句中把NUMERIC字段转成BIGINT类型,Rust侧不需要改依赖、不需要换类型,直接用i64接收:

for row in client.query("SELECT time_col, price::BIGINT FROM pricetable;", &[])? {
    let time: DateTime<Utc> = row.get(0);
    let price: i64 = row.get(1);
    println!("found datum: {} {} ", time, price);
}

注意:如果字段存在小数、或者数值超过i64取值范围,这个转换会直接在数据库侧抛出错误。

关于自定义类型实现trait的说明

这种方式只适合有特殊转换逻辑的场景,不是读取NUMERIC类型的唯一方案,官方提供的feature已经覆盖了绝大多数常规使用场景,没必要重复实现解析逻辑。如果确实有自定义需求,可以参考postgres crate内置的rust_decimal/bigdecimal适配的源码逻辑,按NUMERIC的二进制格式解析即可。


内容的提问来源于stack exchange,提问作者rtviii

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.30 20:36:33