Is there a way to perform an index access to an instance of a struct like this:
struct MyStruct {
// ...
}
impl MyStruct {
// ...
}
fn main() {
let s = MyStruct::new();
s["something"] = 533; // This is what I need
}
Is there a way to perform an index access to an instance of a struct like this:
struct MyStruct {
// ...
}
impl MyStruct {
// ...
}
fn main() {
let s = MyStruct::new();
s["something"] = 533; // This is what I need
}
You can use the Index
and IndexMut
traits.
use std::ops::{Index, IndexMut};
struct Foo {
x: i32,
y: i32,
}
impl Index<&'_ str> for Foo {
type Output = i32;
fn index(&self, s: &str) -> &i32 {
match s {
"x" => &self.x,
"y" => &self.y,
_ => panic!("unknown field: {}", s),
}
}
}
impl IndexMut<&'_ str> for Foo {
fn index_mut(&mut self, s: &str) -> &mut i32 {
match s {
"x" => &mut self.x,
"y" => &mut self.y,
_ => panic!("unknown field: {}", s),
}
}
}
fn main() {
let mut foo = Foo { x: 0, y: 0 };
foo["y"] += 2;
println!("x: {}", foo["x"]);
println!("y: {}", foo["y"]);
}
It prints:
x: 0
y: 2
You want to use the Index
trait (and its pair IndexMut
):
use std::ops::Index;
#[derive(Copy, Clone)]
struct Foo;
struct Bar;
impl Index<Bar> for Foo {
type Output = Foo;
fn index<'a>(&'a self, _index: Bar) -> &'a Foo {
println!("Indexing!");
self
}
}
fn main() {
Foo[Bar];
}
You may have a problem if the fields in MyStruct
are not homogeneous in their type (e.g. not all i32
). Then Index
/IndexMut
will be a bit trickier to use. You'd be in core::any::Any
land with reflection and trait objects and would use something like bevy_reflect
.
Alternatively, instead of Index
/IndexMut
where you're looking to get a ref or ref mut to a node, you could try serde::Serialize
/serde::Deserialize
as a means of accessing tme. That solves your type issue. Using your code from the question, below is the complete implementation using miniconf.
The trait supports accessing nodes by usize
numeric field index or by &str
field name. It works fine for deeper hierarchies, arrays and nested structs (the example below already shows some of that) and supports any serde
backend (showing JSON for convenience here).
use miniconf::{JsonCoreSlash, Miniconf};
#[derive(Miniconf)]
struct MyStruct {
something: i32,
#[miniconf(defer(2))]
other: [Option<u8>; 10],
}
fn main() {
let mut s = MyStruct {
something: 99,
other: [Some(3); 10],
};
s.set_json("/something", b"533").unwrap();
assert_eq!(s.something, 533);
s.set_json("/other/4", b"21").unwrap();
assert_eq!(s.other[4], Some(21));
}
Similar questions have been asked under: