gpt4 book ai didi

json - 在 Rust 中读取 Json

转载 作者:行者123 更新时间:2023-11-29 07:49:21 24 4
gpt4 key购买 nike

我正在尝试读取 Rust 中的 Json 文件的内容。此文件包含平面中的点数组,如 [[1, 2], [3.5, 2.7], [0, -2.1]] .

我第一次尝试实现是

extern crate serialize;
use serialize::json;
use std::io::File;

fn read_points() -> Vec<[f64, ..2]> {
let contents = File::open(&Path::new("../points.json")).read_to_string().unwrap();
let points: Vec<Vec<f64>> = json::decode(contents.as_slice()).unwrap();

points.iter().map(|&v| [v[0], v[1]]).collect::<Vec<[f64, ..2]>>()
}

现在我有两个问题。

首先,我得到一个编译错误

error: cannot move out of dereference of `&`-pointer

这似乎暗示我的 map 操作不安全。作为 Rust 的新手,对我来说 &v 在哪里并不明显驻留在内存中。理想情况下,我想访问支持 Vec<f64> 的底层数组。 ,或者甚至更好,避免分配内部向量并直接读取 json 到 Vec<[f64, ..2]> .

其次 - 但不太重要 - 有两个丑陋的 unwrap电话。现在,我明白读取文件和解析 json 都可能失败。有没有办法轻松组合Result实例,例如 flatmap在 Scala 或 bind在 haskell ?更好的是,类似 do 符号的东西?

最佳答案

对于你的第二个问题,是的,有and_then() Result 上的方法,但我担心它在这里不起作用,因为错误类型不同:read_to_string()返回 Result<String, IoError>同时 json::decode()返回 Result<T, DecoderError> ,而且你不能只是组合它们——在 Rust 中没有通用的方法来描述类型的联合,所以你不能表达组合的错误类型。

有计划来简化错误处理,它们在 this 中涵盖。和 this RFC,所以也许这种情况将来会有所改善。

现在回答主要问题。

因为您使用的是 iter(),所以您会收到有关移出取消引用的编译错误并同时在闭包参数中取消引用模式。此方法返回一个迭代器,该迭代器将 引用 生成到向量中 - 满足 Iterator<&Vec<f64>> 的东西边界。这意味着您无法通过此迭代器将值从向量中移出,因为无法将值从引用中移出。

然而,&v模式意味着 v 应该从引用中移出,即这个闭包:

|&v| [v[0], v[1]]  // v is Vec<f64>

相当于这个:

|r| {              // r is &Vec<f64>
let v = *r; // v is Vec<f64>
[v[0], v[1]]
}

此模式仅对可隐式复制的类型有用,例如 int ,或用于解构枚举/元组/等,但是Vec<T>不是隐式可复制的,因为它有一个析构函数,这里没有解构发生。

首先,您可以离开&&v完全(您也不需要为 collect() 指定类型参数,因为它将从函数返回类型中推断出来):

points.iter().map(|v| [v[0], v[1]]).collect()

之所以可以这样做,是因为索引运算符被转换为自动取消引用其目标的特征方法调用。

但是,如果使用 into_iter() 会更好地表达意图而不是 iter() :

points.into_iter().map(|v| [v[0], v[1]]).collect()

into_iter()Vec<T>返回一个产生 T 的迭代器, 不是 &T喜欢iter() , 所以 v这里的类型是 Vec<f64> . into_iter()消耗了它的目标,但是因为 points在此调用后不使用,这样做是安全的,它更好地表达了 points 的事实转化为结果。

但是还有更好的方法。 JSON 解码器不支持反序列化静态大小的数组,如 [f64, ..2]因为它需要在泛型参数中支持数字,而 Rust 还没有。但是你总是可以编写自己的类型并实现 Decodable为此:

extern crate serialize;

use serialize::{Decoder, Decodable};
use serialize::json;

#[deriving(Show)]
struct Point(f64, f64);

impl Decodable for Point {
fn decode<D: Decoder>(d: &mut D) -> Result<Point, D::Error> {
d.read_tuple(2, |d| {
d.read_tuple_arg(0, |d| d.read_f64()).and_then(|e1|
d.read_tuple_arg(1, |d| d.read_f64()).map(|e2|
Point(e1, e2)
)
)
})
}
}

fn main() {
let s = "[[1, 2], [3.5, 2.7], [0, -2.1]]";
let v: Vec<Point> = json::decode(s).unwrap();
println!("{}", v);
}

(试一试 here )

现在如果你需要[f64, ..2]你总是可以添加一个方法到 Point struct 将为您构造它。

不幸的是, Decodable Decoder 现在确实记录不足,所以你必须依靠常识并检查 rustc --pretty=expanded当您尝试实现它们时输出。

编辑更新为最新的 Rust 版本

关于json - 在 Rust 中读取 Json,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/26336281/

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com