对于第二个问题,是的,Result 上有 and_then() 方法,但我担心它在这里不起作用,因为错误类型不同:read_to_string() 返回Result<String, IoError> 而json::decode()返回Result<T, DecoderError>,你不能只是组合它们——在Rust中没有描述类型联合的通用方法,所以你不能表达组合的错误类型。
有计划减轻错误处理,this 和 this RFC 涵盖了这些问题,因此这种情况可能会在未来得到改善。
现在是主要问题的答案。
由于您同时在闭包参数中使用iter() 和取消引用模式,因此您会收到关于退出取消引用的编译错误。此方法返回一个迭代器,该迭代器将 references 生成到向量中 - 满足Iterator<&Vec<f64>> bound。这意味着您无法通过此迭代器将值从向量中移出,因为无法将值移出引用。
但是,&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() on Vec<T> 返回一个迭代器,它产生T,而不是像iter() 那样的&T,所以这里的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 结构添加一个方法,该结构将为您构建它。
不幸的是,Decodable 和 Decoder 现在的文档确实不足,因此当您尝试实现它们时,您必须依靠常识并检查 rustc --pretty=expanded 输出。
编辑使用最新的 Rust 版本更新