如何在我的 serde_json::Value 包装器类型上实现 valuable::Valuable。
除数组和对象之外,所有其他字段均可以工作。
我尝试用我的自定义类型包装它,但它给出了编译错误,说值被删除了。
我也尝试为我的自定义类型添加生命周期,但这也不起作用。
这是我目前所做的,希望有一个解决方案,甚至一个替代方案。
use serde_json::{Map, Value as Json};
use valuable::{Mappable, Valuable, Value, Visit};
#[derive(Clone)]
pub struct JsonValueable(pub Json);
#[derive(Clone)]
pub struct JsonValueableMap(pub Map<String, Json>);
impl Valuable for JsonValueable {
fn as_value(&self) -> Value<'_> {
match self.0 {
Json::Array(ref array) => array
.iter()
.map(|v| JsonValueable(v.clone()))
.collect::<Vec<JsonValueable>>()
.as_value(),
Json::Bool(ref value) => value.as_value(),
Json::Number(ref num) => {
if num.is_f64() {
Value::F64(num.as_f64().unwrap())
} else if num.is_i64() {
Value::I64(num.as_i64().unwrap())
} else {
unreachable!()
}
}
Json::Null => Value::Unit,
Json::String(ref s) => s.as_value(),
Json::Object(ref object) => JsonValueableMap(object.clone()).as_value(),
}
}
fn visit(&self, visit: &mut dyn Visit) {
match self.0 {
Json::Array(ref array) => array
.iter()
.map(|v| JsonValueable(v.clone()))
.for_each(|v| v.visit(visit)),
Json::Bool(ref value) => value.visit(visit),
Json::Number(ref num) => {
if num.is_f64() {
num.as_f64().unwrap().visit(visit)
} else if num.is_i64() {
num.as_i64().unwrap().visit(visit)
} else {
unreachable!()
}
}
Json::Null => Value::Unit.visit(visit),
Json::String(ref s) => s.visit(visit),
Json::Object(ref object) => JsonValueableMap(object.clone()).visit(visit),
}
}
}
impl Valuable for JsonValueableMap {
fn as_value(&self) -> Value<'_> {
Value::Mappable(self)
}
fn visit(&self, visit: &mut dyn Visit) {
for (k, v) in self.0.iter() {
visit.visit_entry(k.as_value(), JsonValueable(v.clone()).as_value());
}
}
}
impl Mappable for JsonValueableMap {
fn size_hint(&self) -> (usize, Option<usize>) {
let len = self.0.len();
(len, Some(len))
}
}
这是我遇到的错误
error[E0515]: cannot return value referencing temporary value
--> bins/api/src/utils/json_valuable.rs:14:39
|
14 | Json::Array(ref array) => array
| _______________________________________^
| |_______________________________________|
15 | || .iter()
16 | || .map(|v| JsonValueable(v.clone()))
17 | || .collect::<Vec<JsonValueable>>()
| ||________________________________________________- temporary value created here
18 | | .as_value(),
| |____________________________^ returns a value referencing data owned by the current function
error[E0515]: cannot return value referencing temporary value
--> bins/api/src/utils/json_valuable.rs:31:41
|
31 | Json::Object(ref object) => JsonValueableMap(object.clone()).as_value(),
| --------------------------------^^^^^^^^^^^
| |
| returns a value referencing data owned by the current function
| temporary value created here
For more information about this error, try `rustc --explain E0515`.
error: could not compile `api` (bin "api") due to 2 previous errors
我只看到一个选项——透明的新类型和一点点
unsafe
。总而言之,您需要返回一个,
valuable::Value
但所有嵌套的变量都需要引用——为了返回它们,它们必须来自您的self
,而不是中间值。理想情况下,您应该直接返回&serde_json::Map
一个,&dyn Mappable
但当然,该实现尚未定义,您也无法定义。下面的代码展示了如何从使用相同生命周期的
&JsonValueableMap
a 中获取 a :&Map<String, Json>
这就是
Path::new
工作原理。这样,Valuable
for 语句JsonValueable
就变得简单了:您也需要创建自己的代码
JsonValuableArray
,并且可能需要提供相同的代码,以便在其他地方JsonValuable
跳过更多.clone()
s 。以下是完整的实现(由于没有 s ,因此无法在 Playground 上编译valuable
)。如果您不想
unsafe
直接在代码中使用任何内容,那么可以使用ref-cast包来为您完成此操作。