Cannot move out of index of

#[derive(Debug)]
pub struct StringObject {
    object_string: Value,
    methods: Value,
}

impl StringObject {
    pub fn new<T: AsRef<str>>(string: T) -> Self {
        let object_string = from_str(string.as_ref()).unwrap_or(Value::String((" ".to_string())));
        Self {
            object_string: object_string["data"],
            methods: object_string["type"],
        }
    }
}

error: cannot move out of index of Value
move occurs because value has type Value, which does not implement the Copy trait

The underlying issue you are seeing is that indexing will try to move the value unless it is immediately put behind a reference.

container[index] is actually syntactic sugar for *container.index(index) , but only when used as an immutable value. If a mutable value is requested, IndexMut is used instead. This allows nice things such as let value = v[index] if the type of value implements Copy .

std::ops::Index

The easy solution is to clone() the values.

use serde_json::{from_str, Value};

#[derive(Debug)]
pub struct StringObject {
    object_string: Value,
    methods: Value,
}

impl StringObject {
    pub fn new<T: AsRef<str>>(string: T) -> Self {
        let object_string = from_str(string.as_ref()).unwrap_or(Value::String(" ".to_string()));
        Self {
            object_string: object_string["data"].clone(),
            methods: object_string["type"].clone(),
        }
    }
}

(playground)

If you want to avoid the unnecessary copies, instead of deserializing into a temporary value (object_string) you could make serde_json::from_str() deserialize to a StringObject directly.

You'll typically do this by deriving the Deserialize trait and using #[serde(rename = "...")] to tell it what names to use when deserializing a particular field.

use serde::Deserialize;
use serde_json::{from_str, Value};

#[derive(Debug, Deserialize)]
pub struct StringObject {
    #[serde(rename = "data")]
    object_string: Value,
    #[serde(rename = "type")]
    methods: Value,
}

impl StringObject {
    pub fn new<T: AsRef<str>>(string: T) -> Self {
        serde_json::from_str(string.as_ref()).unwrap()
    }
}

(playground)

1 Like

thank you .
could you tell me some suggestion how to stduy rust?
i'm js coder, it's difficult to code rust. T.T

It all depends on your learning style. I normally recommend that people read The Rust Programming Language (often just called The Book) because that'll give you an introduction to most of the language syntax and sorts of things you'll use every day.

The book also teaches you what is idiomatic in Rust, and what patterns you may try to bring from another language that don't really work for Rust (e.g. JS likes to use lots of callbacks that close over variables, but that's a bit harder in Rust because it often uses shared mutation).

From there it's like learning any other programming language - write some code, struggle on something basic, google the error message, realise you were staring at the solution the entire time, get your code working again, rinse and repeat.

Something I found really useful early on is just browsing the standard library's API docs. In general, Rust has a really good story around API documentation, but the standard library is especially good with runnable examples for most types or functions (e.g. std::fs::File), explanations of how a particular trait is intended to be implemented (e.g. std::hash::Hash), and even pages for specific keywords that link to further information (e.g. if).

Clicking through the standard library docs is also great for just understanding what is out there without needing 3rd party crates.

2 Likes

thank you

1 Like

This topic was automatically closed 90 days after the last reply. We invite you to open a new topic if you have further questions or comments.