How to index struct values of different types

Viewed 72

I'm new to Rust, probably missing something obvious. I have the following code with the main idea of being able to index any struct field like so struct_instance['field'].

use std::ops::Index;

enum Selection {
    Full,
    Partial,
}

struct Config {
    display: bool,
    timeout: u16,
    selection: Selection,
}

impl Index<&'_ str> for Config {
    type Output = bool;

    fn index(&self, index: &'_ str) -> &Self::Output {
        match index {
            "display" => &self.display,
            _ => panic!("Unknown field: {}", index),
        }
    }
}

fn main() {
    let config = Config {
        display: true,
        timeout: 500,
        selection: Selection::Partial,
    };

    let display = config["display"];

    println!("{display}");
}

The problem is: I can not find a way to index every type of struct fields, because associated type Output doesn't let me define more than one type. I would want to have match being able to process all Config fields somehow, is there a way to do so?

1 Answers

As answered apilat , Index is for array like structures.

However if you want, you can achieve this with enums.

  1. Create enum with all available types of config fields (bool, u16, Selection, etc...)
  2. Change Config fields' types to this new enum
  3. Change the Output in the Index impl again to this new enum

Here is full code example

use std::ops::Index;

#[derive(Debug)]
enum ConfigField {
    Display(bool),
    Timeout(u16),
    Selection(Selection)
}

#[derive(Debug)]
enum Selection {
    Full,
    Partial,
}

struct Config {
    display: ConfigField,
    timeout: ConfigField,
    selection: ConfigField,
}

impl Index<&'_ str> for Config {
    type Output = ConfigField;

    fn index(&self, index: &'_ str) -> &Self::Output {
        match index {
            "display" => &self.display,
            "timeout" => &self.timeout,
            "selection" => &self.selection,
            _ => panic!("Unknown field: {}", index),
        }
    }
}

fn main() {
    let config = Config {
        display: ConfigField::Display(true),
        timeout: ConfigField::Timeout(500),
        selection: ConfigField::Selection(Selection::Partial),
    };

    let display = &config["display"];
    let timeout = &config["timeout"];
    let selection = &config["selection"];

    println!("{:?} {:?} {:?}", display, timeout, selection);
}
Related