0

Assume we have a Person struct and a PersonName struct that used by a field, like the following:

struct Person {
    name: PersonName,
    age: u8,
}

struct PersonName {
    name: String,
    middle_name: Option<String>,
    surname: Option<String>,
}

Create the struct:

let foo = Person { name: PersonName{name: String::from("bar"), middle_name: None, surname: String::from("baz") }, age: 16u8 };

How can I use this string to gain access to the struct field specified in it?

let foo_surname = eval("name.surname") // returns "baz"
// struct evaluator returns the value of specific field
// i.e.: field_path: "my_struct_field.sub_field1.sub_sub_field_1"
fn eval(field_path: String) -> ...{}

Is there any way to do this without writing a custom evaluator?

2
  • You can do this by creating you own trait and create you own derive macro for this trait. But it is VERY complicated to be described here. Commented Apr 2, 2021 at 8:52
  • This question is similar to: Access struct field by variable. If you believe it’s different, please edit the question, make it clear how it’s different and/or how the answers on that question are not helpful for your problem. Commented Aug 16, 2024 at 3:53

2 Answers 2

1

There is no way to do this. Rust is a statically compiled language where this kind of information doesn't existing anymore during the program runtime.

Sign up to request clarification or add additional context in comments.

Comments

0

There are at least two possible approaches.

If you must return the actual heterogeneous (u8 vs String) data from that eval(), you'll need to wrap it in an enum and write a match on the field_path along the lines of this answer: https://stackoverflow.com/a/73676114/22362561

However, in many cases you can get around this by serializing the data to hold the heterogeneous types. Here is a solution using miniconf (disclaimer: I develop that crate) with '/' as the path hierarchy separator and JSON as the serialization format:

use miniconf::{JsonCoreSlash, Tree};

#[derive(Tree)]
struct Person {
    #[tree]
    name: PersonName,
    age: u8,
}

#[derive(Tree)]
struct PersonName {
    name: String,
    middle_name: Option<String>,
    surname: Option<String>,
}

impl Person {
    fn eval(&self, key: &str) -> String {
        let mut buf = vec![0; 128];
        let len = self.get_json(key, &mut buf).unwrap();
        buf.truncate(len);
        String::from_utf8(buf).unwrap()
    }
}

fn main() {
    let foo = Person {
        name: PersonName {
            name: "bar".into(),
            middle_name: None,
            surname: Some("baz".into()),
        },
        age: 16u8,
    };
    assert_eq!(foo.eval("/name/surname"), "\"baz\"");
    assert_eq!(foo.eval("/age"), "16");
}

Note that you can plug in other serialization backends (ser_raw comes to mind) and also other path hierarchy separators.

Similar:

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.