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

在Diesel+Sqlite环境下,如何通过FromSql trait实现Rust枚举的字节转换?

问题:Diesel+Sqlite下Rust枚举与Text类型转换编译错误

我正在使用Diesel库和Sqlite数据库,尝试创建以diesel::sql_types::Text类型存储到数据库的Rust枚举,但参考示例代码后仍无法正常运行,出现编译错误。

我的代码如下:

#[derive(PartialEq, Eq, AsExpression, FromSqlRow, Serialize, Deserialize, Clone, Debug)]
#[diesel(sql_type = diesel::sql_types::Text)]
pub enum InspectionType {
    #[serde(rename = "RUNWAY")]
    Runway,

    #[serde(rename = "PAPI")]
    Papi,
}

impl serialize::ToSql<Text, Sqlite> for InspectionType {
    fn to_sql(&self, out: &mut serialize::Output<Sqlite>) -> serialize::Result {
        match *self {
            InspectionType::Runway => out.write_all(b"RUNWAY")?,
            InspectionType::Papi => out.write_all(b"PAPI")?,
        }

        Ok(IsNull::No)
    }
}

impl deserialize::FromSql<Text, Sqlite> for InspectionType {
    fn from_sql(bytes: SqliteValue) -> deserialize::Result<Self> {
        match bytes.as_bytes() {
            b"RUNWAY" => Ok(InspectionType::Runway),
            b"PAPI" => Ok(InspectionType::Papi),
            _ => Err("Unrecognized enum variant".into()),
        }
    }
}

编译报错信息:

error[E0599]: no method named `as_bytes` found for struct `SqliteValue` in the current scope
  --> src/app_data/inspection.rs:40:21
   |
40 |         match bytes.as_bytes() {
   |                     ^^^^^^^^ method not found in `SqliteValue<'_, '_, '_>`

解决方法

问题根源

Diesel的SqliteValue类型API在版本迭代中发生了变化,旧版本的as_bytes()方法已被移除,需要使用read()方法来读取字节内容。

修正后的FromSql实现

use diesel::deserialize::{self, FromSql};
use diesel::sqlite::Sqlite;
use diesel::sql_types::Text;
use diesel::sqlite::SqliteValue;

impl FromSql<Text, Sqlite> for InspectionType {
    fn from_sql(value: SqliteValue) -> deserialize::Result<Self> {
        let bytes = value.read::<&[u8]>()?;
        match bytes {
            b"RUNWAY" => Ok(InspectionType::Runway),
            b"PAPI" => Ok(InspectionType::Papi),
            _ => Err("Unrecognized InspectionType variant".into()),
        }
    }
}

简化ToSql实现的可选方案

如果希望避免手动匹配枚举值和字符串,可以利用serde的序列化结果来简化实现(注意要去除serde自动添加的引号):

use diesel::serialize::{self, ToSql, Output, IsNull};
use diesel::sqlite::Sqlite;
use diesel::sql_types::Text;

impl ToSql<Text, Sqlite> for InspectionType {
    fn to_sql(&self, out: &mut Output<Sqlite>) -> serialize::Result {
        let serialized = serde_json::to_string(self)?;
        let raw_str = serialized.trim_matches('"');
        out.write_all(raw_str.as_bytes())?;
        Ok(IsNull::No)
    }
}

如果不需要依赖serde的重命名逻辑,也可以直接手动映射字符串:

impl ToSql<Text, Sqlite> for InspectionType {
    fn to_sql(&self, out: &mut Output<Sqlite>) -> serialize::Result {
        let value_str = match self {
            InspectionType::Runway => "RUNWAY",
            InspectionType::Papi => "PAPI",
        };
        out.write_all(value_str.as_bytes())?;
        Ok(IsNull::No)
    }
}

内容的提问来源于stack exchange,提问作者Kacper Ledwosiński

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.07 01:28:14