Assuming you’d be okay with fully exposing the contained Vec/HashMap (so that users of your API can e.g. obtain a &mut Row or a &mut HashMap<Key, Value>), there’s the option of using the Deref+DerefMut trait for achieving behavior similar to delegating all of Vec’s or HashMap methods. Well, at least all of the &self and &mut self methods, not the constructors, or into_iter[1], etc… you’ll see yourself, feel free to given an impl Deref for List { type Target = Row; … } impl DerefMut for List { … } a try and see whether or not if fits your use-case.
So you’d need to implement the IntoIterator trait yourself; for convenience maybe also for &List and &mut List, delegating to .iter() and .iter_mut() accordingly. ↩︎
Deref and DerefMut aren't supposed to be used for imitating inheritance. But you don't need them; you can just expose the inner data structures via normal inherent methods.
Personnally, that's what I would do (it's what I have done in the past). But using the name as_inner[_mut]. The borrowing rules makes APIs like that feasible while they wouldn't be in other languages (other languages could keep references alive for longer than you'd want).
users have to be aware of inner which is really just an implementation detail;
users have to type more.
That's why using Deref is so attractive. But at the same time I don't want to go against what the docs recommend, so ISTM that wrapping as much of the API as is needed is the least worst solution.
later...
In the end I opted to provide wrappers for the most commonly needed methods (e.g., get, get_mut, [], push, truncate, clear) and inner and inner_mut to make the whole Vec API available.
I really think that it would be nice if Rust offered some solution to this. I realise that anything inheritance-like brings with it the risk of method name clashes etc.
Anyway, one kind of idea might be something along the lines of:
#[derive(Clone, Debug)]
pub struct List {
vtype: String,
comment: String,
values: Vec<Value>,
}
impl List {
// new and getter/setter for vtype & comment & other List-specific methods
}
impl Delegate for List {
type inner = values;
}
The Delegate would mean, that given lst of type List when the compiler looks to resolve a method, say, lst.method(), if method() isn't in impl List, then since List is a Delegate, the compiler would then try lst.inner.method() where inner is values, i.e., lst.values.method(). This would at least have the virtue of hiding an implementation detail; but I guess it isn't practical.