【问题标题】:Deserializing redis's Value in Rust (FromRedisValue)在 Rust 中反序列化 redis 的值 (FromRedisValue)
【发布时间】:2021-06-15 08:54:14
【问题描述】:

我正在 Rust 中使用 redis 实现一个简单的任务队列,但我正在努力将 redis 的返回值反序列化为我的自定义类型。

我一共想到了 3 个方法:

  1. 使用serde-redis反序列化
  2. 手动实现 FromRedisValue 特征
  3. 使用serde-json 序列化为字符串> 作为字符串发送> 然后从字符串反序列化

第 3 种方法有效,但感觉不自然。我想弄清楚 1 或 2,这两个我都失败了。

方法 1 - serde-redis

我有一个简单的任务定义:

#[derive(Debug, PartialEq, serde::Deserialize, serde::Serialize)]
pub struct Task {
    pub id: u32,
    pub desc: String,
}

我正试图接收到一个工人:

use serde_redis::RedisDeserialize;

pub fn execute_task(conn: &mut Connection) {
    let task: Task = redis::cmd("LPOP")
        .arg("task_q")
        .query::<Task>(conn)
        .unwrap()
        .deserialize()
        .unwrap();

    println!("... executing task {} ...", task.id);
}

但我收到以下错误:

error[E0277]: the trait bound `Task: FromRedisValue` is not satisfied
  --> src/bin/worker.rs:38:10
   |
38 |         .query::<Task>(conn)
   |          ^^^^^ the trait `FromRedisValue` is not implemented for `Task`

error[E0599]: no method named `deserialize` found for struct `Task` in the current scope
  --> src/bin/worker.rs:40:10
   |
40 |         .deserialize()
   |          ^^^^^^^^^^^ method not found in `Task`

很明显,我错误地集成了箱子,因为它不起作用。文档非常简短,作为初学者,我的源代码在我头上 - 我会错过什么?

方法 2 - 手动实现 FromRedisValue

我的幼稚做法:

impl FromRedisValue for Task {
    fn from_redis_value(v: &Value) -> RedisResult<Self> {
        let t = Task {
            id: v.id,
            desc: v.desc,
        };
        RedisResult::Ok(t)
    }

    fn from_redis_values(items: &[Value]) -> RedisResult<Vec<Self>> {
        let tasks = items
            .into_iter()
            .map(|v| Task {
                id: v.id,
                desc: v.desc,
            })
            .collect();
        RedisResult::Ok(tasks)
    }
}

我遇到的错误:

error[E0609]: no field `id` on type `&Value`
   --> src/redis_tut.rs:203:19
    |
203 |             id: v.id,
    |                   ^^

error[E0609]: no field `desc` on type `&Value`
   --> src/redis_tut.rs:204:21
    |
204 |             desc: v.desc,
    |                     ^^^^

// ...the same for the vector implementation

很明显,redis 的值没有/不知道我想要的任务字段。这样做的正确方法是什么?

【问题讨论】:

    标签: rust redis serde


    【解决方案1】:

    Redis 没有定义结构化的序列化格式。它主要存储字符串和整数。所以你必须为你的结构选择或定义你的格式。

    如您所见,一种流行的方法是 JSON,但如果您只想(反)序列化简单的 (id, description) 对,它的可读性不强,也不方便。

    在这种情况下,您可以定义自己的格式,例如,id 和描述之间用破折号:

    #[derive(Debug, PartialEq)]
    pub struct Task {
        pub id: u32,
        pub desc: String,
    }
    // assume a task is defined as "<id>-<desc>"
    impl FromRedisValue for Task {
        fn from_redis_value(v: &Value) -> RedisResult<Self> {
            let v: String = from_redis_value(v)?;
            if let Some((id, desc)) = v.split_once('-') {
                if let Ok(id) = id.parse() {
                    Ok(Task {
                        id,
                        desc: desc.to_string(),
                    })
                } else {
                    Err((ErrorKind::TypeError, "bad first token").into())
                }
            } else {
                Err((ErrorKind::TypeError, "missing dash").into())
            }
        }
    }
    

    【讨论】:

    • 很有趣,所以在这个解决方案中,当我将结构发送到 redis 时,我会编写一个转换为 - 的“to_str()”方法,对吗?这与我现在拥有的是 json_serde::to_str() 和另一端的 json_serde::from_str() 相比?
    • 是的。如果这是描述任务的自然方式,您还可以利用 Display 特征,这意味着您将使用 to_string,它在您实现该特征时自动可用。
    【解决方案2】:

    我实际上为这种问题编写了一个板条箱,它提供了实现来自 mitsuhiko / redis-rs 的 redis::FromRedisValue 和 redis::ToRedisArgs 特征的派生宏,其中每个字段的类型也实现了 ToRedisArgs。看看redis-redive

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2015-08-28
      • 2018-10-06
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2021-08-28
      • 2022-12-21
      • 2023-02-22
      相关资源
      最近更新 更多