eddy
eddy

Reputation: 518

How do you abstract generics in nested Rust types?

struct Disk<T: Read + Seek + Write> {
    handle: T,
}

struct Partition<T: Read + Seek + Write> {
    disk: Disk<T>,
}

struct File<T: Read + Seek + Write> {
    partition: Partition<T>,
}

At the point of struct Partition, it is no longer interesting what Disks trait-bounds are. Through the language design, it is not possible to create a Disk with a handle what does not have Read + Seek + Write. Through this example is very simple, types might become extremely complex if they have multiple members with traits.

What I want is:

struct Disk<T: Read + Seek + Write> {
    handle: T,
}

type ExDisk = FIXME;

struct Partition {
    disk: ExDisk,
}

struct File {
    partition: Partition,
}

Upvotes: 3

Views: 2497

Answers (1)

Matthieu M.
Matthieu M.

Reputation: 300349

How do you abstract generics in nested types?

Rust does abstractions by traits; so use a trait (not a type).

Specifically, Partition should depend on a generic parameter implementing a trait rather than on Disk<T: ...> itself.

trait Volume {}

struct Disk<T: Read + Seek + Write> {
    handle: T,
}

impl<T: Read + Seek + Write> Volume for Disk<T> {}

struct Partition<V: Volume> {
    volume: V,
}

struct File<V: Volume> {
    partition: Partition<V>,
}

Alternatively File could itself depend on an abstract partition.

Note that using this Volume trait, it is even possible to remove the generic parameter completely; as long as the Volume trait is object-safe and the object behind does not need to store a local reference:

struct Partition {
    volume: Box<Volume>,
}

struct File {
    partition: Partition,
}

It adds a tiny bit of over-head (a dynamic allocation + indirect calls), but gives you a single type instead of a family.


Another solution to only reduce verbosity is to introduce a new trait for specifically this purpose:

trait Volume: Read + Seek + Write {}

impl<T> Volume for T where T: Read + Seek + Write {}

Allows you to thereafter use the Volume trait as a short-hand for the sum of traits it represents. This does not abstract the disk, but is certainly convenient.

Upvotes: 5

Related Questions