type ExInterface interface { ... }
type ExStruct {
arr []ExInterface
}
Each element of arr need not be the same type, so long as it implements ExInterface. In Rust, the only thing I can do that is similar is:
struct<t: ExTrait> ExStruct {
arr: Vec<t>,
}
Which means that each element of arr not only has to implement ExTrait, but also has to be of consistent type with the rest of the elements. If I want the same level of flexibility the Go gives me, I need to make an enum of each possible type that arr can contain.
To elaborate a bit on the sibling comment here, Rust makes things a bit more explicit than Go does. A Go interface type is actually a pointer (of sorts), since you don't generally want to store things of different types and sizes in a single array. For example, if you have:
type StructOne struct {
field uint32
}
type StructTwo struct {
field uint64
}
It's pretty clear that these structures are of different size. Now, if both of these structures implement the "Foo" interface, we can't simply make an array like []Foo, since we'd have no practical method to index into the array. Go solves this by making []Foo actually be an array of pointers.
However, Rust's philosophy is, AFAIK, "be explicit about the cost you pay". So, if you want to make an "array of things that implement Foo", you need to explicitly put the "things" behind a pointer, or a Box<>. So, you get:
struct MyStruct {
arr: Vec<Box<Foo>>,
}
Which makes it explicit that you're storing a "list of pointers to things that implement Foo". Of course, the nice part is that you can use generic syntax to make an array that doesn't use pointers, like so:
struct MyStruct2<T: Foo> {
arr: Vec<T>,
}
In the above, you can only store items of a single type in the `arr` field, and the generics constrain that to be only types `T` that implement Foo. The upside is, however, that you don't have any pointer indirection (and the compiler monomorphizes - i.e. generates new code for each generic implementation), so your code is probably faster / easier for LLVM to optimize.
The gist of the issue is this: a Vec (and most other collections) needs all items to be sized and of the same size in-memory to lay itself out (know how much memory to reserve for each item for instance), and it stores its stuff inline. So a Vec<u8>'s buffer looks like this:
[u8|u8|u8|u8]
and a Vec for a struct { u8, u32, u8 } looks like this (ignoring padding):
[u8,u32,u8|u8,u32,u8|u8,u32,u8|u8,u32,u8]
If you want to store both A and B inline in a Vec you've got trouble: that they both implement Foo doesn't mean they have the same size at all (and they often don't), and Rust's type system doesn't allow it anyway (`A: Foo` says that A implements Foo, but the function or collection still gets an A via reification and monomorphisation).
The alternative is to do what languages Java or Go do under the covers: add a fixed-size pointer as indirection between the collection and the actual items (the pointer is actually fat, you get a pointer to the instance itself and a pointer to the vtable for the trait implementation, I think Go does the same but java doesn't as each instance has its classpointer), so you get e.g.
[&A|&A|&B|&A]
all pointers are the same size and things work out. More generally than trait objects, you need to do this to store any unsized type (http://doc.rust-lang.org/book/unsized-types.html) in something which only accepts sized types.