Implement Index trait with generic type parameter

Hi,

Given this snippet

use std::ops::Index;

pub struct NodeIndex(pub usize);

pub struct Node<T>(T);

// this does not compile
impl<T> Index<NodeIndex> for Vec<Node<T>> {
    type Output = Node<T>;

    fn index(&self, index: NodeIndex) -> &Self::Output {
        &self[index.0]
    }
}

pub struct Graph<T> {
    pub nodes: Vec<Node<T>>,
}

impl<T> Graph<T> {
    pub fn new() -> Graph<T> {
        Graph { nodes: vec![] }
    }
}

pub struct Stuff(u32);

fn main() {
    let mut graph = Graph::<Stuff>::new();
    graph.nodes.push(Node(Stuff(1)));
    graph.nodes.push(Node(Stuff(2)));
    graph.nodes.push(Node(Stuff(3)));
    let index = NodeIndex(1);
    let value = &graph.nodes[index.0]; // without the Index trait implemented
    let value = &graph.nodes[index]; // with the Index trait implemented

}

I have the following error:

Compiling rust v0.1.0 (/home/pierre/Documents/test)
error[E0210]: type parameter T must be used as the type parameter for some local type (e.g., MyStruct<T>)
--> src/main.rs:8:6
|
8 | impl Index for Vec<Node> {
| ^ type parameter T must be used as the type parameter for some local type
|
= note: only traits defined in the current crate can be implemented for a type parameter

It seems that because Node uses a generic type parameter (T), it causes problem. But I have no clue on how to get this work. Can you help me please ?

You can't. Index is already implemented for Vec - you can only implement traits you created, or traits on types you created. You can wrap Vec in a newtype and implement Index for that, though:

struct NodeVec<T>(Vec<Node<T>>);

impl<T> Index<NodeIndex> for NodeVec<T> {
    type Output = Node<T>;

    fn index(&self, index: NodeIndex) -> &Self::Output {
        &self.0[index.0]
    }
}

If I change Node for something like struct Node(u32) instead and if I adapt the rest of the code, it works. So It is possible even if Index is already implemented for Vec. So I don't understand your answer.

Why do you want to use Index though?
It's slower than calling .get() and it will panic if the index is out of bounds, while .get() will just return None, allowing for recovery.

I've asked myself a couple of times in the past why the trait was ever even included; other than the fancy syntax it doesn't really have much to offer.

Thank for your point but please that is not the question, stay in topic.

I think it will now be allowed with RFC 2451, imminent in Rust 1.41.

3 Likes

Oh thank you @cuviper to pointing this here ! This is exactly the case I encounter and this explains why it does not work.
:+1:

Hi,

Since @cuviper told me about this RFC, I wanted to tell at everyone that the pull request about this RFC has been merged !
So now the feature is enabled with rustc 1.41.0 and now my code works as expected. So cool :+1:

1 Like

This topic was automatically closed 90 days after the last reply. New replies are no longer allowed.