3

I am building a command-line application. I have the following trait:

trait ValidatedCommand {
    type Output;
    fn run() -> Result<Self::Output, std::io::Error>;
}

and I have the following two implementations for it:

struct First;
impl ValidatedCommand for First {
    type Output = i32;
    fn run() -> Result<i32, std::io::Error> {
        Ok(1)
    }
}
impl First {
    fn new() -> First {
        First {}
    }
}

struct Second;
impl ValidatedCommand for Second {
    type Output = String;
    fn run() -> Result<String, std::io::Error> {
        Ok(String::from("hello"))
    }
}
impl Second {
    fn new() -> Second {
        Second {}
    }
}

Both structs implement the trait, one returning a String and the other an i32.

I'm trying to create a Vec of that trait, but I'm not sure how to go about it. I tried the following:

fn main() {
    let commands: Vec<dyn ValidatedCommand> = vec![First::new(), Second::new()];

playground.

which errors with

error[E0191]: the value of the associated type `Output` (from the trait `ValidatedCommand`) must be specified
  --> src/main.rs:33:23
   |
2  |     type Output;
   |     ------------ `Output` defined here
...
33 |     let commands: Vec<dyn ValidatedCommand> = vec![First::new(), Second::new()];
   |                       ^^^^^^^^^^^^^^^^^^^^ associated type `Output` must be specified

error[E0277]: the size for values of type `dyn ValidatedCommand` cannot be known at compilation time
  --> src/main.rs:33:19
   |
33 |     let commands: Vec<dyn ValidatedCommand> = vec![First::new(), Second::new()];
   |                   ^^^^^^^^^^^^^^^^^^^^^^^^^ doesn't have a size known at compile-time
   |
   = help: the trait `std::marker::Sized` is not implemented for `dyn ValidatedCommand`
   = note: to learn more, visit <https://doc.rust-lang.org/book/second-edition/ch19-04-advanced-types.html#dynamically-sized-types-and-the-sized-trait>
   = note: required by `std::vec::Vec`

error[E0038]: the trait `ValidatedCommand` cannot be made into an object
  --> src/main.rs:33:19
   |
33 |     let commands: Vec<dyn ValidatedCommand> = vec![First::new(), Second::new()];
   |                   ^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `ValidatedCommand` cannot be made into an object
   |
   = note: method `run` has no receiver

error[E0308]: mismatched types
  --> src/main.rs:33:52
   |
33 |     let commands: Vec<dyn ValidatedCommand> = vec![First::new(), Second::new()];
   |                                                    ^^^^^^^^^^^^ expected trait ValidatedCommand, found struct `First`
   |
   = note: expected type `dyn ValidatedCommand`
              found type `First`

error[E0277]: the size for values of type `dyn ValidatedCommand` cannot be known at compilation time
  --> src/main.rs:33:47
   |
33 |     let commands: Vec<dyn ValidatedCommand> = vec![First::new(), Second::new()];
   |                                               ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ doesn't have a size known at compile-time
   |
   = help: the trait `std::marker::Sized` is not implemented for `dyn ValidatedCommand`
   = note: to learn more, visit <https://doc.rust-lang.org/book/second-edition/ch19-04-advanced-types.html#dynamically-sized-types-and-the-sized-trait>
   = note: required by `std::slice::<impl [T]>::into_vec`
   = note: this error originates in a macro outside of the current crate (in Nightly builds, run with -Z external-macro-backtrace for more info)

error[E0277]: the size for values of type `dyn ValidatedCommand` cannot be known at compilation time
  --> src/main.rs:33:47
   |
33 |     let commands: Vec<dyn ValidatedCommand> = vec![First::new(), Second::new()];
   |                                               ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ doesn't have a size known at compile-time
   |
   = help: the trait `std::marker::Sized` is not implemented for `dyn ValidatedCommand`
   = note: to learn more, visit <https://doc.rust-lang.org/book/second-edition/ch19-04-advanced-types.html#dynamically-sized-types-and-the-sized-trait>
   = note: slice and array elements must have `Sized` type
   = note: this error originates in a macro outside of the current crate (in Nightly builds, run with -Z external-macro-backtrace for more info)

error[E0038]: the trait `ValidatedCommand` cannot be made into an object
  --> src/main.rs:33:47
   |
33 |     let commands: Vec<dyn ValidatedCommand> = vec![First::new(), Second::new()];
   |                                               ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `ValidatedCommand` cannot be made into an object
   |
   = note: method `run` has no receiver
   = note: this error originates in a macro outside of the current crate (in Nightly builds, run with -Z external-macro-backtrace for more info)

error[E0277]: the size for values of type `dyn ValidatedCommand` cannot be known at compilation time
  --> src/main.rs:33:47
   |
33 |     let commands: Vec<dyn ValidatedCommand> = vec![First::new(), Second::new()];
   |                                               ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ doesn't have a size known at compile-time
   |
   = help: the trait `std::marker::Sized` is not implemented for `dyn ValidatedCommand`
   = note: to learn more, visit <https://doc.rust-lang.org/book/second-edition/ch19-04-advanced-types.html#dynamically-sized-types-and-the-sized-trait>
   = note: required by `std::vec::Vec`
   = note: this error originates in a macro outside of the current crate (in Nightly builds, run with -Z external-macro-backtrace for more info)

error[E0038]: the trait `ValidatedCommand` cannot be made into an object
  --> src/main.rs:33:47
   |
33 |     let commands: Vec<dyn ValidatedCommand> = vec![First::new(), Second::new()];
   |                                               ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `ValidatedCommand` cannot be made into an object
   |
   = note: method `run` has no receiver
   = note: this error originates in a macro outside of the current crate (in Nightly builds, run with -Z external-macro-backtrace for more info)

I am thinking that maybe there is a way to make use of the associated type, but I have no idea how I might go about it.

Is there a way to get this vector creation to compile?

Shepmaster
  • 388,571
  • 95
  • 1,107
  • 1,366
Geo
  • 93,257
  • 117
  • 344
  • 520
  • 1
    Possible duplicate of [Vector of objects belonging to a trait](https://stackoverflow.com/questions/25818082/vector-of-objects-belonging-to-a-trait) (+ notice [this comment](https://stackoverflow.com/questions/25818082/vector-of-objects-belonging-to-a-trait#comment94219043_25819164)). – Andrey Tyukin Jan 28 '19 at 21:31
  • @AndreyTyukin I was using that post to make some changes to mine. Made me realize some things that I was doing wrong. – Geo Jan 28 '19 at 21:34
  • 1
    is it still wrong, or has the problem resolved itself after the dozen of edits? ;) Your code is still not exactly an [mcve] because of the omitted code `...`. You could have copy-pasted the method signatures and replaced the irrelevant implementations by `unimplemented!()` to make it compile (or rather, "not compile", but in the interesting way). Or just skip some of the methods from the `trait` altogether... – Andrey Tyukin Jan 28 '19 at 21:35
  • Please review how to create a [MCVE] and then [edit] your question to include it. There are numerous types and functions that are missing, which makes reproducing your error message impossible without a lot of guessing. Try to produce something that reproduces your error on the [Rust Playground](https://play.rust-lang.org) or you can reproduce it in a brand new Cargo project. There are [Rust-specific MCVE tips](//stackoverflow.com/tags/rust/info) as well. – Shepmaster Jan 28 '19 at 21:36
  • Added the link, sorry you guys had to guess. – Geo Jan 28 '19 at 21:44
  • @Geo That's a great MCVE. But now I ask myself how you would want to use it? Even if you somehow managed to store them in the same `Vec`, what would you do with the `Output`s of unknown type? – Andrey Tyukin Jan 28 '19 at 21:53
  • @AndreyTyukin It's very possible I'm still trying to write Java in Rust :). In the original implementation, I was actually using a HashMap of String to ValidatedCommand, as I wanted the String to be sent by the user, lookup the command and run it. I thought that for example purposes, once I'd know how to do it with a Vec, I'd be able to adapt the same for the HashMap. – Geo Jan 28 '19 at 22:04
  • @Geo Again, assuming that you can store it in the `Vec` and `run` it: the function signature of `run` is `run<'a>(&mut self, matches: &'a ArgMatches) -> Result`, so it will give you a `Self::Output`. What do you want to do with it once you get it? It's "something" of an unknown type, of unknown size. You can't even cast it to anything meaningfully. Are you sure that you wanted `dyn Trait`s with associated types and not a simple `enum`? – Andrey Tyukin Jan 28 '19 at 22:21
  • @AndreyTyukin I'm not sure I want `dyn Trait`, I was just trying to create the code ( and learn some Rust in the process ) from examples and articles I found online. Basically, I just want to have a set of commands that have something in common, and each could return a different type as the Ok branch of the Result. – Geo Jan 28 '19 at 22:40
  • @Geo Since you mentioned Java: on the JVM, the easiest way to do something like what you described in a type safe way would be using `case class`es in Scala. In Rust, that would correspond to the `enum` types. I'd suggest to take a closer look at Rust `enum`s and algebraic data types in general: people coming from Java / Python often seem to miss this feature. – Andrey Tyukin Jan 28 '19 at 22:48
  • Another way to see it: You wanted something like `Vec>>` with an unspecified associated type. This roughly corresponds to wildcard parameters in Java generics, which in turn corresponds to existential type, which is, from type-theory point of view, something like an *infinite* sum type indexed by all possible types. In contrast, `enum`s roughly correspond to a *finite* sum of the listed cases. So, my proposal would be: whenever you feel like you want to have a "wildcard" in the type, consider replacing it with an `enum` (i.e. replace "infinite sum" by "finite sum"). – Andrey Tyukin Jan 29 '19 at 12:57

0 Answers0