-2

I'm trying to set up a tree structure in Rust, but I've run into an issue with how to store the list of nodes, which store different types of values, and therefore have different type parameters.

A simplified version of the problem is below:

struct Node<T> {
    pub props: T,
    pub children: Vec<Node>
}

fn main() {
    let node = Node {
        props: (42, 6),
        children: vec![Node {
            props: Some("potatoes"),
            children: vec![]
        }]
    };
}

This fails to compile with the following error:

error[E0243]: wrong number of type arguments: expected 1, found 0
 --> src/main.rs:4:19
  |
4 |     children: Vec<Node>
  |                   ^^^^ expected 1 type argument

I can't provide a type argument, since it must be allowed to be anything. What's the best way to go about doing this?

I've looked at this question, but it doesn't address type arguments.

vpzomtrrfrt
  • 483
  • 6
  • 16
  • It would *seem* like it would implicitly require a second type parameter, say `Q`, such that the children of `Node` are `Node`, but then... Would an associated type be the answer? No, because associated types are for traits... – MutantOctopus Mar 27 '18 at 04:00
  • 1
    Hang on. "store different types of values, and therefore have different type parameters." Provided I'm reading that right, unless they're [Trait Objects](https://doc.rust-lang.org/book/first-edition/trait-objects.html), that wouldn't fly in a statically typed language liked Rust. – MutantOctopus Mar 27 '18 at 04:24
  • Please [edit] your question to explain why the answers to [How do I create a heterogeneous collection of objects?](https://stackoverflow.com/q/27957103/155423) don't answer your question. – Shepmaster Mar 27 '18 at 11:58
  • 1
    The duplicate does indeed address your question: your type argument `T` can be monomorphised into a `Box`: `Node>`. – E_net4 Mar 27 '18 at 15:22

2 Answers2

0

If you want to store different types of values, first ascertain what are all the types of values you would want to store. Then define an enum as such:

enum Value {
    Pair(i32, i32),
    MayBeStr(Option<&'static str>),
    ... // any value that you would like to store
}

And wire it up like:

struct Node {
    pub props: Value,
    pub children: Vec<Node>
}

fn main() {
    let node = Node {
        props: Value::Pair(42, 6),
        children: vec![Node {
            props: Value::MayBeStr(Some("potatoes")),
            children: vec![]
        }]
    };
}

Link to Playground

pepsighan
  • 798
  • 9
  • 17
0

The best solution I've come up with so far is to add a trait to all the items and use Boxes to store them. For this example:

trait Props {}

impl Props for (i32, i32) {}
impl<'a> Props for Option<&'a str> {}

struct Node<'a> {
    pub props: Box<Props + 'a>,
    pub children: Vec<Node<'a>>
}

fn main() {
    let node = Node {
        props: Box::new((42, 6)),
        children: vec![Node {
            props: Box::new(Some("potatoes")),
            children: vec![]
        }]
    };
}
vpzomtrrfrt
  • 483
  • 6
  • 16