在 rust 中处理具有通用和非通用类型的枚举 return
Handling return of enum with generic and non generic type in rust
我正在尝试在 Rust 中创建条带化的 redis 克隆。我在尝试实现 redis 协议时遇到了困难。
我想要一个结构来封装传入的数据包并将其适当地解析为其数据类型和命令。
我的数据类型是简单的字符串或整数,但是我想使用的数组数据类型有点不同Vec<T>
,这就是我的问题开始的地方。
所以我创建了代表传入数据包的结构。
想要用这个结构存档就可以做什么:
let parsed_value = ProtocolPacket::new(data: &[u8])
struct ProtocolPacket <T> { // <-- this <T> is only because of ProtocolPacketData<T>
command: ProtocolPacketCommand,
data: ProtocolPacketData<T>,
}
impl <T>ProtocolPacket <T> {
fn new(packet: &[u8]) -> ProtocolPacket<T> {
let packet = packet.into_iter();
let command = ProtocolPacketCommand::new(packet.next().unwrap()); // <-- This is working
// Delete \r \n
packet.next_back().unwrap();
packet.next_back().unwrap();
let data = packet.as_slice();
let data = ProtocolPacketData::new(data);
ProtocolPacket{
command: command,
data: data,
}
}
enum ProtocolPacketData <T> {
SimpleString(String),
Error(String),
Integer(i64),
String(String),
Array(Vec<T>),
}
impl <T> ProtocolPacketData <T> {
pub fn new(rest: &[u8]) -> ProtocolPacketData<T> {
let rest = rest.into_iter();
let data_type = rest.next().unwrap();
// Strip last 2 bytes -> \r\n
rest.next_back().unwrap();
rest.next_back().unwrap();
match data_type.to_string().chars().next().unwrap() {
'+' => handle_packet_simplestring(rest.as_slice()), <-- Function call that returns ProtocolPacketData<String>
'-' => unimplemented!()
':' => unimplemented!()
'$' => unimplemented!()
'*' => unimplemented!()
'%' => unimplemented!()
_ => unimplemented!()
}
}
}
fn handle_packet_simplestring<T>(packet_value: &[u8]) -> ProtocolPacketData<String>{
let data = String::from_utf8_lossy(packet_value);
ProtocolPacketData::SimpleString(data.to_string())
}
这是我的错误发生的地方
match data_type.to_string().chars().next().unwrap() {
'+' => handle_packet_simplestring(rest.as_slice()), <-- Function call that returns ProtocolPacketData<String>
'-' => unimplemented!()
':' => unimplemented!()
'$' => unimplemented!()
'*' => unimplemented!()
'%' => unimplemented!()
_ => unimplemented!()
}
我收到一个错误
mismatched types
expected enum ProtocolPacketData<T>
found enum ProtocolPacketData<std::string::String>
我怎样才能做到这一点,这是可行的方法吗?
谢谢,山姆
问题是你实际上是在欺骗编译器。 impl<T> ProtocolPacketData<T>
意味着 ProtocolPacketData<T>
的“外部”可以决定 它 想要 T
成为什么并且 impl
必须适用.例如,一个人应该能够做到 let x: ProtocolPacketData::<f64> = ProtocolPacketData::new(&buffer)
;但是 handle_packet_simplestring
然后将 String
放在必须 f64
的位置。编译器试图告诉你:它期望 ProtocolPacketData<T>
- 对 T
没有限制 - 但你返回了 specific ProtocolPacketData<String>
(到因为 unimplemented!()
returns !
,所以编译器认为在任何情况下它都必须是 String
,而不管 T
).
您可能想要完全删除 T
参数并扩展 ProtocolPacketData
例如
enum ProtocolPacketData {
// ...
StringArray(Vec<Box<str>>),
IntArray(Vec<u64>),
// ...
}
你的大 match
返回一个特定的变体。
另一种可能性是
enum ProtocolPacketData {
// ...
Array(Vec<ProtocolPacketData>),
}
这使得 Array
变体更简单;但它允许异构数组 ([Integer, String, Array[String, String]]
),这可能不是您想要的。
我正在尝试在 Rust 中创建条带化的 redis 克隆。我在尝试实现 redis 协议时遇到了困难。 我想要一个结构来封装传入的数据包并将其适当地解析为其数据类型和命令。
我的数据类型是简单的字符串或整数,但是我想使用的数组数据类型有点不同Vec<T>
,这就是我的问题开始的地方。
所以我创建了代表传入数据包的结构。
想要用这个结构存档就可以做什么:
let parsed_value = ProtocolPacket::new(data: &[u8])
struct ProtocolPacket <T> { // <-- this <T> is only because of ProtocolPacketData<T>
command: ProtocolPacketCommand,
data: ProtocolPacketData<T>,
}
impl <T>ProtocolPacket <T> {
fn new(packet: &[u8]) -> ProtocolPacket<T> {
let packet = packet.into_iter();
let command = ProtocolPacketCommand::new(packet.next().unwrap()); // <-- This is working
// Delete \r \n
packet.next_back().unwrap();
packet.next_back().unwrap();
let data = packet.as_slice();
let data = ProtocolPacketData::new(data);
ProtocolPacket{
command: command,
data: data,
}
}
enum ProtocolPacketData <T> {
SimpleString(String),
Error(String),
Integer(i64),
String(String),
Array(Vec<T>),
}
impl <T> ProtocolPacketData <T> {
pub fn new(rest: &[u8]) -> ProtocolPacketData<T> {
let rest = rest.into_iter();
let data_type = rest.next().unwrap();
// Strip last 2 bytes -> \r\n
rest.next_back().unwrap();
rest.next_back().unwrap();
match data_type.to_string().chars().next().unwrap() {
'+' => handle_packet_simplestring(rest.as_slice()), <-- Function call that returns ProtocolPacketData<String>
'-' => unimplemented!()
':' => unimplemented!()
'$' => unimplemented!()
'*' => unimplemented!()
'%' => unimplemented!()
_ => unimplemented!()
}
}
}
fn handle_packet_simplestring<T>(packet_value: &[u8]) -> ProtocolPacketData<String>{
let data = String::from_utf8_lossy(packet_value);
ProtocolPacketData::SimpleString(data.to_string())
}
这是我的错误发生的地方
match data_type.to_string().chars().next().unwrap() {
'+' => handle_packet_simplestring(rest.as_slice()), <-- Function call that returns ProtocolPacketData<String>
'-' => unimplemented!()
':' => unimplemented!()
'$' => unimplemented!()
'*' => unimplemented!()
'%' => unimplemented!()
_ => unimplemented!()
}
我收到一个错误
mismatched types
expected enum ProtocolPacketData<T>
found enum ProtocolPacketData<std::string::String>
我怎样才能做到这一点,这是可行的方法吗? 谢谢,山姆
问题是你实际上是在欺骗编译器。 impl<T> ProtocolPacketData<T>
意味着 ProtocolPacketData<T>
的“外部”可以决定 它 想要 T
成为什么并且 impl
必须适用.例如,一个人应该能够做到 let x: ProtocolPacketData::<f64> = ProtocolPacketData::new(&buffer)
;但是 handle_packet_simplestring
然后将 String
放在必须 f64
的位置。编译器试图告诉你:它期望 ProtocolPacketData<T>
- 对 T
没有限制 - 但你返回了 specific ProtocolPacketData<String>
(到因为 unimplemented!()
returns !
,所以编译器认为在任何情况下它都必须是 String
,而不管 T
).
您可能想要完全删除 T
参数并扩展 ProtocolPacketData
例如
enum ProtocolPacketData {
// ...
StringArray(Vec<Box<str>>),
IntArray(Vec<u64>),
// ...
}
你的大 match
返回一个特定的变体。
另一种可能性是
enum ProtocolPacketData {
// ...
Array(Vec<ProtocolPacketData>),
}
这使得 Array
变体更简单;但它允许异构数组 ([Integer, String, Array[String, String]]
),这可能不是您想要的。