Is there a way I can access an attribute of a struct by a string?
No. Names of fields of a struct
don't even exist in the running program. They're completely removed at compile time.
You can map names to fields manually (and write a macro if you need this often):
match name {
"foo" => s.foo,
"bar" => s.bar,
"baz" => s.baz,
_ => panic!("unknown field"),
}
However, depending on what you're really trying to achieve, there may be better ways than accessing fields by string.
For example, if you're reading some kind of input into a struct, see serde. If you're mapping options to values, perhaps a regular Rust enum
would work.
Here is a method that does what you asked, but as @kornel wrote there is going to be a better way to do what you are trying to do. If you say more about your use case then people can provide better guidance.
#[macro_use]
extern crate serde_derive;
extern crate serde;
extern crate serde_value;
use serde::Serialize;
use serde::de::DeserializeOwned;
use serde_value::Value;
#[derive(Serialize)]
struct Justmike2000 {
a: String,
b: String,
c: u64,
}
fn get_field_by_name<T, R>(data: T, field: &str) -> R
where
T: Serialize,
R: DeserializeOwned,
{
let mut map = match serde_value::to_value(data) {
Ok(Value::Map(map)) => map,
_ => panic!("expected a struct"),
};
let key = Value::String(field.to_owned());
let value = match map.remove(&key) {
Some(value) => value,
None => panic!("no such field"),
};
match R::deserialize(value) {
Ok(r) => r,
Err(_) => panic!("wrong type?"),
}
}
fn main() {
let j = Justmike2000 {
a: "string A".to_owned(),
b: "string B".to_owned(),
c: 1,
};
let a: String = get_field_by_name(&j, "a");
println!("a = {:?}", a);
let b: String = get_field_by_name(&j, "b");
println!("b = {:?}", b);
let c: u64 = get_field_by_name(&j, "c");
println!("c = {:?}", c);
}
Thanks for your answer: I was going to learn how to do that with a macro, but in my simple case is better your match solution