Consider the following code where I am trying to use the enum Field to look-up indices in the data list.
#[repr(usize)]
#[derive(Debug)]
enum Field {
Uid = 0,
Id = 1,
Name = 2,
}
pub fn main() {
let data = [
[String::from("X1"), String::from("A"), String::from("Car")],
[String::from("Z1"), String::from("A"), String::from("Truck")],
[String::from("Y1"), String::from("A"), String::from("Train")],
];
for item in data.iter() {
// Instead of data[2] and data[1], we use values from enum
// which map to 1 and 2 to make the code more readable.
println!("Name: {}; Id: {}", item[Field::Name], item[Field::Id])
}
}
Compiling playground v0.0.1 (/playground)
error[E0277]: the type `[std::string::String]` cannot be indexed by `Field`
--> src/main.rs:17:38
|
17 | println!("Name: {}; Id: {}", item[Field::Name], item[Field::Id])
| ^^^^^^^^^^^^^^^^^ slice indices are of type `usize` or ranges of `usize`
|
= help: the trait `std::slice::SliceIndex<[std::string::String]>` is not implemented for `Field`
= note: required because of the requirements on the impl of `std::ops::Index<Field>` for `[std::string::String]`
It seems enum do not behave the way I am assuming they do. How can I achieve this behavior in Rust? Either I can improve the use of enum or there is some other construct that I can use here?
(Note: While a vec! with struct can be used to initialise data with the named fields, the purpose here is to understand how to get the above approach working when the data type available is a list.)
Edit: Corrected code sample for typo and updated the playground.
use std::ops::Index;
#[repr(usize)]
#[derive(Debug)]
enum Field {
Uid = 0,
Id = 1,
Name = 2,
}
struct FieldArray([String; 3]);
impl Index<Field> for FieldArray {
type Output = String;
fn index(&self, idx: Field) -> &Self::Output { &self.0[idx as usize] }
}
pub fn main() {
let data = [
FieldArray([String::from("X1"), String::from("A"), String::from("Car")]),
FieldArray([String::from("Z1"), String::from("A"), String::from("Truck")]),
FieldArray([String::from("Y1"), String::from("A"), String::from("Train")]),
];
for item in data.iter() {
// Instead of data[2] and data[1], we use values from enum
// which map to 1 and 2 to make the code more readable.
println!("Name: {}; Id: {}", item[Field::Name], item[Field::Id])
}
}
if you don't actually ever need to construct a Field, this is by far shortest:
#[allow(non_snake_case,non_upper_case_globals)]
mod Field {
pub const Uid: usize = 0;
pub const Id: usize = 1;
pub const Name: usize = 2;
}
pub fn main() {
let data = [
[String::from("X1"), String::from("A"), String::from("Car")],
[String::from("Z1"), String::from("A"), String::from("Truck")],
[String::from("Y1"), String::from("A"), String::from("Train")],
];
for item in data.iter() {
// Instead of data[2] and data[1], we use values from enum
// which map to 1 and 2 to make the code more readable.
println!("Name: {}; Id: {}", item[Field::Name], item[Field::Id])
}
}