1

I'm trying to return a vector from a function but the compiler gives me the following error message:

 expected `Foo<T>`,
    found `Foo<&str>`
(expected type parameter,
    found &-ptr) [E0308]

What am I missing here?

struct Foo<T> {
    bar: T,
}


fn foos<T>() -> Vec<Foo<T>> {
    vec![
        Foo { bar: "x" },
        Foo { bar: 1 },
    ]
}



fn main() {
    let my_foos: Vec<_> = foos();

    println!("{}", my_foos[0].bar);
}
caio
  • 1,949
  • 16
  • 20

1 Answers1

2

The compiler is giving you a good error message here:

expected `Foo<T>`,
   found `Foo<&str>`

That is, you aren't returning some generic T, you are returning a concrete type. Actually, you aren't returning just one type, you are trying to return two different types!

Each time a generic is resolved, it must resolve to a single type. That is, you can call foo<T>(a: T, b: T) with two u32 or two bool, but not with one of each.

To make your code work in the most straight-forward way, you can use an enum. This creates a single type that can have one of a set of values:

struct Foo<T> {
    bar: T,
}

#[derive(Debug)]
enum Bar<'a> {
    Num(i32),
    Str(&'a str),
}

// Note no generics here, we specify the concrete type that this `Foo` is
fn foos() -> Vec<Foo<Bar<'static>>> {
    vec![
        Foo { bar: Bar::Str("x") },
        Foo { bar: Bar::Num(1) },
    ]
}

fn main() {
    let my_foos: Vec<_> = foos();

    println!("{:?}", my_foos[0].bar);
}
Shepmaster
  • 388,571
  • 95
  • 1,107
  • 1,366
  • 1
    Isn't it possible to return *any* values without making them explicit? For example, any structs that implements a certain trait? Something like: "fn foos -> Vec> {}" – caio Apr 11 '15 at 19:22
  • 1
    @caio in your example, you have specified concrete type(s) in the body of the function - what benefit would there be to making it generic? The biggest I am aware of is to hide implementation details. What are you looking to do? – Shepmaster Apr 11 '15 at 19:34
  • 1
    @caio That signature, to be internally consistent and to support some (admittedly rarer) useful patterns, needs to allow the caller to ask for *any* concrete type, as long as it's `Renderable`. What you want would need a new feature, like the closed [RFC PR 105 (abstract unboxed return types)](https://github.com/rust-lang/rfcs/pull/105). You can use `Box` but that has a hefty cost. –  Apr 11 '15 at 19:35
  • @Shepmaster What I'm trying to do is: `patterns` is a list (vector) of `structs` that implements `Renderable` methods. I want to walk through the list of patterns, find the first who match the given pattern and call the `render` method in that struct. But structs will be created on demand and patterns can hold many of them. What I need is to make patterns return a list of these structs but defining all of them in an enum is painful. – caio Apr 11 '15 at 20:05
  • just adding some info: by "given pattern" I mean a regular expression. pseudo code: patterns = my_patterns(); for pattern in patterns { if (match("foo", pattern.regex)) { render(pattern) } } – caio Apr 11 '15 at 20:16
  • @caio it sounds like you want what @delnan said - the (not available) RFC, or to have a `Vec>`. – Shepmaster Apr 11 '15 at 20:27
  • @Shepmaster @delnan do you mean something like this? `let x: Box = Box::new(Bar { value: "x" });` If so, how can I access `x.value`? – caio Apr 11 '15 at 21:39
  • 1
    @caio You can't, unless the trait has a method that gives access. But that has nothing to do with the `Box`, only with the fact that you want to use the trait instead of the concrete type (`Bar`). –  Apr 11 '15 at 21:41
  • @delnan I tried to create a method in the trait but it also didn't work. The method looks like this: `fn render(&self) -> &'static str { self.value }` – caio Apr 11 '15 at 21:44
  • 1
    @caio this is fairly far from your original question - perhaps opening a new one? They are free to open ^_^ – Shepmaster Apr 11 '15 at 21:49
  • @Shepmaster Here we go: http://stackoverflow.com/questions/29583709/access-a-field-from-a-struct-casted-with-boxtrait – caio Apr 11 '15 at 22:17