How to handle such feedback by get(index)

I have a struct named MyData, I want to get data by index, and if the index is invalid a error happen, it should be captured.
how to write the code, thanks advanced.

use std::{vec, ops::Index};
use thiserror::Error;       //thiserror = "1.0.31"

#[derive(Debug, Error)]
enum MyErr{
    #[error("xx")]
    getErr{ from:String}
}
type MyResult<T> = std::result::Result<T, MyErr>;

#[derive(Debug)]
struct MyData {
    name:String,
    data: Vec<i32>
}

impl Index<usize> for MyData {
    type Output = MyResult<i32>;     //or :  type Output = Option<i32>; 
    fn index(&self, index: usize) -> &Self::Output {
        &self.data.get(index).unwrap_or(||{
            MyErr::getErr { from: "index not valid".to_string() }       //err happened here ,but it warns not correct..
        })?                     //my question here: how to write the code to return a MyResult<i32>
    }
}

fn main(){
    let a = MyData { name: "a".to_string(), data: vec![1,2,3,4,5]};
    let b = a[113];             //get by index: 113, of course it's None value, I wanna get this error here.
    println!("{}", b);
}

Index::index must return a reference: Index in std::ops - Rust

So if you want to return a result, the only option you have is to use something other than [] syntax. For example, slices have a get method.

2 Likes

Note that this expression:

    let b = a[113];

desugars to something like

    // note the `*` dereference
    let b = *<MyData as Index<usize>>::index(&a, 113);

And the idea is that a[113] is a place expression representing the memory directly in your struct. This is why indexing requires you to return a reference -- the idea is that this indexing something analogous to a field access -- you should be returning a reference to some data which is owned by your struct. A Result is not part of your struct.

(The dereferencing is also why you have to use a reference in let x = &v[42] when you have a Vec of non-Copy types to avoid moving out of the Vec, even though you're returning a reference in the implementation.)

1 Like

Dear, I understand the key point, so I changed the output to Option but still warn,
is it possible to impl Index for such struct and get by index?

use std::{vec, ops::Index};
use thiserror::Error;       //thiserror = "1.0.31"

#[derive(Debug, Error)]
enum MyErr{
    #[error("xx")]
    getErr{ from:String}
}
type MyResult<T> = std::result::Result<T, MyErr>;

#[derive(Debug)]
struct MyData {
    name:String,
    data: Vec<i32>
}

impl Index<usize> for MyData {
    type Output = Option<i32>;  //change the output to Option,
    fn index(&self, index: usize) -> &Self::Output {
        &self.data.get(index)           //warn: expected reference &Option<i32>, found reference &Option<&i32>
    }
}

fn main(){
    let a = MyData { name: "a".to_string(), data: vec![1,2,3,4,5]};
    let b = a[113];
                 //get by index: 113, of course it's None value, I wanna get this error here.
    // println!("{}", b);
}

Dear,
yes, I understand the case, I changed to code output to Option but still remain the warn,
is it possible to impl index for the struct like this way?
if not I think I should find other methods.

I posted the revised code again above.

The general pattern used by the standard library is that fallible lookups get their own methods that return Option (e.g. HashMap::get() returns Option<&V>) and lookups which should always succeed (i.e. failures can only happen due to a programming bug) will use the Index trait and trigger a panic. Typically this will be implemented as a self.get(...).expect("value not found"), like in HashMap.

2 Likes