Tuesday 15 January 2013

Read Json in Rust -



Read Json in Rust -

i trying read contents of json file in rust. file contains array of points in plane, [[1, 2], [3.5, 2.7], [0, -2.1]].

my first effort @ implementation is

extern crate serialize; utilize serialize::json; utilize std::io::file; fn read_points() -> vec<[f64, ..2]> { allow contents = file::open(&path::new("../points.json")).read_to_string().unwrap(); allow points: vec<vec<f64>> = json::decode(contents.as_slice()).unwrap(); points.iter().map(|&v| [v[0], v[1]]).collect::<vec<[f64, ..2]>>() }

now have 2 problems this.

first, compile error

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

which seems imply map operation not safe. beingness finish newbie rust, not obvious me &v resides in memory. ideally, access underlying array backing vec<f64>, or better, avoid allocate inner vectors read straight json vec<[f64, ..2]>.

second - less of import - there 2 ugly unwrap calls. now, understand both reading file , parsing json may fail. there way combine result instances, such flatmap in scala or bind in haskell? better, notation?

for sec question, yes, there and_then() method on result, i'm afraid won't work here because error types different: read_to_string() returns result<string, ioerror> while json::decode() returns result<t, decodererror>, , can't combine them - there no generic way describe union of types in rust, can't express combined error type.

there plans ease working errors, covered this , this rfcs, maybe situation improve in future.

now reply main question.

you're getting compile error moving out of dereference because you're using iter() , dereference pattern in closure argument @ same time. method returns iterator yields references vector - satisfies iterator<&vec<f64>> bound. means can't move values out vector through iterator because impossible move values out of reference.

however, &v pattern means v should moved out reference, is, closure:

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

is equivalent one:

|r| { // r &vec<f64> allow v = *r; // v vec<f64> [v[0], v[1]] }

this pattern useful types implicitly copyable, int, or destructuring enums/tuples/etc, vec<t> not implicitly copyable because has destructor , no destructuring happens here.

first, can leave & out in &v (you don't need specifying type parameter collect() because inferred function homecoming type):

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

the reason why can index operator translated trait method phone call automatically dereferences target.

however, express intention improve if utilize into_iter() instead of iter():

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

into_iter() on vec<t> returns iterator yields t, not &t iter(), v here of type vec<f64>. into_iter() consumes target, since points not used after call, safe , improve expresses fact points transformed result.

but there improve way. json decoder not back upwards deserializing statically sized arrays [f64, ..2] because requires supporting numbers in generic parameters, , rust not have them yet. can write own type , implement decodable it:

extern crate serialize; utilize serialize::{decoder, decodable}; utilize serialize::json; #[deriving(show)] struct point(f64, f64); impl decodable 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() { allow s = "[[1, 2], [3.5, 2.7], [0, -2.1]]"; allow v: vec<point> = json::decode(s).unwrap(); println!("{}", v); }

(try here)

now if need [f64, ..2] can add together method point struct build you.

unfortunately, decodable , decoder underdocumented have rely on mutual sense , inspect rustc --pretty=expanded output when seek implement them.

edit updated latest rust version

json rust

No comments:

Post a Comment