在 Rust 中反序列化 redis 的值(FromRedisValue)
Deserializing redis's Value in Rust (FromRedisValue)
我在 Rust 中使用 redis 实现了一个简单的任务队列,但我正在努力将 redis 的返回值反序列化为我的自定义类型。
我一共想到了3种方法:
- 反序列化使用serde-redis
- 手动实现
FromRedisValue
特征
- 使用 serde-json 序列化为字符串 > 作为字符串发送 > 然后从字符串反序列化
第三种方法有效但感觉不自然。我想弄清楚 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 的值没有/不知道我想要的任务字段。正确的做法是什么?
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())
}
}
}
我实际上为这类问题写了一个 crate,它提供了 Derive Macros 实现了来自 mitsuhiko / redis-rs 的 redis::FromRedisValue 和 redis::ToRedisArgs 特征,用于每个字段的任何结构类型还实现了 ToRedisArgs。看看 redis-redive.
我在 Rust 中使用 redis 实现了一个简单的任务队列,但我正在努力将 redis 的返回值反序列化为我的自定义类型。
我一共想到了3种方法:
- 反序列化使用serde-redis
- 手动实现
FromRedisValue
特征 - 使用 serde-json 序列化为字符串 > 作为字符串发送 > 然后从字符串反序列化
第三种方法有效但感觉不自然。我想弄清楚 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 的值没有/不知道我想要的任务字段。正确的做法是什么?
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())
}
}
}
我实际上为这类问题写了一个 crate,它提供了 Derive Macros 实现了来自 mitsuhiko / redis-rs 的 redis::FromRedisValue 和 redis::ToRedisArgs 特征,用于每个字段的任何结构类型还实现了 ToRedisArgs。看看 redis-redive.