Yes and no. Let's drill down into this because the details are important.
There's a crucial distinction between input and output types in practice. For a given input type T, Rust makes it possible to abstract over `T`, `&T`, `Cow<'a, T>`, `Arc<T>` etc, by using a trait such as `impl AsRef<T>`.
However, Rust doesn't currently have existential types, so its ability to abstract over output types is more limited. You can implement, for example, `fn foo(&self) -> impl AsRef<T> + '_`, but you can't name that type. So if you want to return an enum, you can't write
```
enum MyEnum {
MyT(impl AsRef<T>),
MyU(impl AsRef<U>),
}
```
Instead, you have to concretize the type somehow, either by boxing things up into a trait object (often but not always possible) or by exposing the generic param:
```
enum MyEnum<RefT, RefU> where RefT: AsRef<T>, MyU: Ref<U> {
MyT(RefT),
MyU(RefU),
}
```
This is a real problem, though one that will be solved through existential types.
> Replacing, say, a concrete type with a trait is about as much work in Rust as it is in Assembly.
I'm not sure what you mean here. I'm not aware of any assembly languages which have traits. Replacing a concrete type with a trait tends to be pretty easy in Rust because mistakes are caught at compile time.