zwl1619
zwl1619

Reputation: 4232

There is an error when traversing a json in Rust

test2.json

[
    {"name":"Lucy","age":18,"achievement":[95,86.5,90]},
    {"name":"Lily","age":19,"achievement":[92.5,89,91]},
    {"name":"Jack","age":20,"achievement":[93,90,93.5]}
]

main.rs

use std::fs::File;
use std::io::BufReader;
use serde_json::{Result as SResult, Value};

fn get_profile() -> SResult<Value> {
    let file = File::open("test2.json").expect("file should open read only");
    let reader = BufReader::new(file);
    let mut v: Value = serde_json::from_reader(reader)?;
    Ok(v.take())
}

fn main() {
    let profiles = get_profile().unwrap();

    for element in profiles.as_array().iter() {
        println!("the value is: {}", element["age"]);
    }
}

error:

λ cargo run
   Compiling hello-rust v0.1.0 (D:\workspace\rust-projects\hello-rust)
error[E0277]: the type `[Value]` cannot be indexed by `&str`
  --> src\main.rs:20:38
   |
20 |         println!("the value is: {}", element["age"]);
   |                                      ^^^^^^^^^^^^^^ slice indices are of type `usize` or ranges of `usize`
   |
   = help: the trait `SliceIndex<[Value]>` is not implemented for `&str`
   = note: required because of the requirements on the impl of `std::ops::Index<&str>` for `Vec<Value>`

For more information about this error, try `rustc --explain E0277`.
error: could not compile `hello-rust` due to previous error

How to fix the issue? Any help please, thanks.

Upvotes: 0

Views: 219

Answers (1)

peterulb
peterulb

Reputation: 2988

You are calling .iter() on an Option<&Vec<Value>>. The iterator yields one value if the Option is a Some, otherwise none.

You can change your loop to this instead, which will yield one Value (here the object) at a time:

for element in profiles.as_array().unwrap().iter() {
  println!("the value is: {}", element["age"]);
}

Note: I'd at least use is_array() etc. to validate the structure and improve error handling (not just unwrap(). You get a lot for free when using structs and Deserialize instead of parsing everything manually.

Example:

    #[derive(Deserialize)]
    struct Profile {
        name: String,
        age: usize,
        achievement: Vec<f64>,
    }

    let profiles: Vec<Profile> =
        serde_json::from_reader(BufReader::new(File::open("test2.json").unwrap())).unwrap();
    for profile in profiles {
        println!("the value is: {}", profile.age);
    }

Upvotes: 2

Related Questions