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

为u128自定义Diesel包装类型时遇编译错误求助

问题解决:Diesel中u128类型的PostgreSQL适配

需求背景

为Diesel默认未支持的u128类型创建自定义类型U128,目标是将原生u128以numeric类型(优先)或文本类型存储到PostgreSQL数据库中。

现有实现代码

自定义U128类型实现

use std::io::Write;
use diesel::{AsExpression, deserialize, FromSqlRow, serialize};
use diesel::deserialize::{FromSql};
use diesel::pg::{Pg};
use diesel::serialize::{IsNull, Output, ToSql};
use diesel::sql_types::{Text};

#[derive(AsExpression, FromSqlRow, Debug, Clone, Copy)]
#[diesel(sql_type = Text)]
pub struct U128(pub u128);

impl ToSql<Text, Pg> for U128 {
    fn to_sql<'b>(&self, out: &mut Output<'b, '_, Pg>) -> serialize::Result {
        write!(out, "{}", self.0.to_string())?;
        Ok(IsNull::No)
    }
}

impl FromSql<Text, Pg> for U128 {
    fn from_sql(bytes: Option<&[u8]>) -> deserialize::Result<Self> {
        let s = String::from_utf8_lossy(bytes.as_bytes());
        Ok(U128(s.parse()?))
    }
}

Diesel结构体定义

#[derive(Queryable, Selectable)]
#[diesel(table_name = crate::schema::balance)]
#[diesel(check_for_backend(diesel::pg::Pg))]
pub struct Balance {
    pub id: i32,
    pub account_name: String,
    pub balance: u128,
}

编译错误信息

error[E0277]: the trait bound `u128: diesel::Queryable<diesel::sql_types::Text, Pg>` is not satisfied
   --> src\models.rs:117:27
    |
117 |     pub balance: u128,
    |                  ^^^^ the trait `diesel::Queryable<diesel::sql_types::Text, Pg>` is not implemented for `u128`
    |
= help: the following other types implement trait `diesel::Queryable<ST, DB>`:
          i8
          i16
          i32
          i64
          u8
          u16
          u32
          u64
        and 2 others
= note: required for `u128` to implement `FromSqlRow<diesel::sql_types::Text, Pg>`
= help: see issue #48214

问题分析与解决方案

核心问题

你定义了自定义U128类型,但结构体Balance中依然使用原生u128作为字段类型。Diesel没有为原生u128实现对应PostgreSQL文本类型的Queryable trait,导致编译失败。另外当前自定义类型用的是Text sql类型,没有满足你优先用numeric存储的需求。

修正步骤

  1. 切换到numeric类型存储
    PostgreSQL的numeric类型支持超大整数,更适合存储u128。修改自定义类型的sql类型为Numeric,并实现对应的序列化/反序列化逻辑:

    use diesel::sql_types::Numeric;
    use bigdecimal::BigDecimal;
    
    #[derive(AsExpression, FromSqlRow, Debug, Clone, Copy)]
    #[diesel(sql_type = Numeric)]
    pub struct U128(pub u128);
    
    impl ToSql<Numeric, Pg> for U128 {
        fn to_sql<'b>(&self, out: &mut Output<'b, '_, Pg>) -> serialize::Result {
            let decimal = BigDecimal::from(self.0);
            decimal.to_sql(out)
        }
    }
    
    impl FromSql<Numeric, Pg> for U128 {
        fn from_sql(bytes: Option<&[u8]>) -> deserialize::Result<Self> {
            let decimal = BigDecimal::from_sql(bytes)?;
            let value = decimal.to_u128()?;
            Ok(U128(value))
        }
    }
    

    注意:需要在Cargo.toml中添加bigdecimal依赖,Diesel的Numeric类型依赖该库处理数值转换。

  2. 修改结构体字段类型
    将Balance结构体中的balance字段类型从u128改为自定义的U128:

    #[derive(Queryable, Selectable)]
    #[diesel(table_name = crate::schema::balance)]
    #[diesel(check_for_backend(diesel::pg::Pg))]
    pub struct Balance {
        pub id: i32,
        pub account_name: String,
        pub balance: U128,
    }
    
  3. 同步数据库schema
    确保数据库表balance中的balance字段类型为numeric(而非text),可以通过Diesel的迁移文件修改:

    ALTER TABLE balance ALTER COLUMN balance TYPE numeric;
    

额外优化

如果需要在代码中方便地在u128和U128之间转换,可以实现From和Into trait:

impl From<u128> for U128 {
    fn from(value: u128) -> Self {
        U128(value)
    }
}

impl From<U128> for u128 {
    fn from(value: U128) -> Self {
        value.0
    }
}

这样就可以直接用U128::from(123)或者let num: u128 = balance.balance.into()来转换。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.04 18:02:52