#mysql #rust
#mysql #Ржавчина
Вопрос:
Я хочу прочитать перечисления из таблицы MySQL, но мне не удается преобразовать строковые перечисления из таблицы в реальные перечисления Rust.
Какие варианты у меня есть? В документации говорится, что я должен реализовать FromValue
функцию:
Cargo.toml
[dependencies]
mysql = "15.1.0"
strum = "0.14.0"
strum_macros = "0.14.0"
use mysql::{
prelude::{ConvIr, FromValue},
Value,
};
use std::str::{from_utf8, FromStr};
use strum_macros::{AsStaticStr, EnumString};
#[derive(Debug, PartialEq, Eq, EnumString, AsStaticStr)]
pub enum UserRole {
ADMIN,
USER,
}
#[derive(Debug)]
pub struct EnumIr {
bytes: Vec<u8>,
}
impl ConvIr<UserRole> for EnumIr {
fn new(v: Value) -> mysql::error::Result<EnumIr> {
match v {
Value::Bytes(bytes) => match from_utf8(amp;*bytes) {
Ok(_) => Ok(EnumIr { bytes: bytes }),
Err(_) => Err(mysql::FromValueError(Value::Bytes(bytes))),
},
v => Err(mysql::FromValueError(v)),
}
}
fn commit(self) -> UserRole {
unsafe { UserRole::from_str(from_utf8(amp;self.bytes).unwrap()).unwrap() }
}
fn rollback(self) -> Value {
Value::Bytes(self.bytes)
}
}
impl FromValue for UserRole {
type Intermediate = EnumIr;
}
fn main() {
println!("Hello, world!");
}
Это завершается ошибкой со следующим сообщением об ошибке:
error[E0053]: method `new` has an incompatible type for trait
--> src/main.rs:20:5
|
20 | fn new(v: Value) -> mysql::error::Result<EnumIr> {
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected struct `mysql_common::value::convert::FromValueError`, found enum `mysql::error::Error`
|
= note: expected type `fn(mysql_common::value::Value) -> std::result::Result<EnumIr, mysql_common::value::convert::FromValueError>`
found type `fn(mysql_common::value::Value) -> std::result::Result<EnumIr, mysql::error::Error>`
Кому-нибудь удалось выполнить преобразование или есть подход получше?
Комментарии:
1. Спасибо за ответ! К сожалению, rust playground не включает mysql crate, поэтому я не могу привести пример. Моя проблема в том, что
fn new(v: Value) -> mysql::Result<EnumIr>
я получаюexpected struct mysql_common::value::convert::FromValueError, found enum mysql::error::Error
, что я пытался вернуть mysql:: FromValueError и mysql::error::FromValueError, но они оба не работают. Однако структура mysql_common::value_convert::FromValueError является частной.2. Извините, это мой первый вопрос, спасибо, что уделили мне время. Приведенный выше код теперь взят из нового проекта cargo. Вы должны иметь возможность скопировать и запустить его, чтобы воспроизвести ошибки компилятора.
3. Процесс, который вы только что прошли, является правильным процессом для того, чтобы задать вопрос в любом контексте; в Stack Overflow, в системе отслеживания проблем, в чате или даже лично; имейте это в виду, и вы получите гораздо лучшие ответы (а также, скорее всего, будете чаще отвечать на свой собственный вопрос).
4. Можете ли вы объяснить, чего вы не понимаете в ошибке компилятора? Здесь говорится, что вам нужно вернуть
FromValueError
но вы возвращаетеmysql::error::Error
; почему вы используете неправильный тип?5. Почему вы ссылаетесь на документацию для версии 1.2.0 , когда используемая вами версия — 15.1.0 ?
Ответ №1:
Как указано в сообщении об ошибке (немного очищено):
expected type `fn(Value) -> Result<EnumIr, FromValueError>`
found type `fn(Value) -> Result<EnumIr, mysql::Error>`
Вы не можете вернуть неправильный тип; это просто фундаментальное условие статически типизированного языка. Вместо этого верните правильный тип: Result<EnumIr, mysql::FromValueError>
.
Я также изменил ваш код, чтобы избежать ложного повторного разбора данных в строку:
#[derive(Debug)]
pub struct EnumIr {
string: String,
}
impl ConvIr<UserRole> for EnumIr {
fn new(v: Value) -> Result<EnumIr, mysql::FromValueError> {
match v {
Value::Bytes(bytes) => match String::from_utf8(bytes) {
Ok(string) => Ok(EnumIr { string }),
Err(e) => Err(mysql::FromValueError(Value::Bytes(e.into_bytes()))),
},
v => Err(mysql::FromValueError(v)),
}
}
fn commit(self) -> UserRole {
self.string.parse().unwrap()
}
fn rollback(self) -> Value {
Value::Bytes(self.string.into_bytes())
}
}
Также кажется, что вам следует попытаться проанализировать перечисление в new
методе, поскольку это единственный, который допускает Result
:
#[derive(Debug)]
pub struct EnumIr {
role: UserRole,
string: String,
}
impl ConvIr<UserRole> for EnumIr {
fn new(v: Value) -> Result<EnumIr, mysql::FromValueError> {
match v {
Value::Bytes(bytes) => match String::from_utf8(bytes) {
Ok(string) => match string.parse() {
Ok(role) => Ok(EnumIr { role, string }),
Err(_) => Err(mysql::FromValueError(Value::Bytes(string.into_bytes()))),
},
Err(e) => Err(mysql::FromValueError(Value::Bytes(e.into_bytes()))),
},
v => Err(mysql::FromValueError(v)),
}
}
fn commit(self) -> UserRole {
self.role
}
fn rollback(self) -> Value {
Value::Bytes(self.string.into_bytes())
}
}
Комментарии:
1. Большое вам спасибо! Я только что проверил в своем более крупном проекте и да: ваш код правильно преобразует значение строки mysql в перечисления rust, так здорово!