Generalize a struct over T or &mut T

Hi, I have a struct with a field that needs to be mutable. I don't want to have to rewrite the entire struct, but it needs to be able to hold either a &mut T or a T.

I have tried this:

pub struct Foo<T, M: AsMut<T>> {mut_ref: M};

but the issue is that AsMut<T> isn't implemented for all T.

I could also do this:

struct RefFoo<'t, T> { // The actual implementation is given to this struct
    bar: &'t mut T
}

struct Foo<'t, T> {
    owned: T,
    bar: RefFoo<'t, T>,
}

fn main() {
    let owned = String::new();
    let bar = RefFoo {bar: &mut owned};

    let foo = Foo {
        owned,
        bar,
    };
}

However the issue here is that Foo contains both the owned and the mutable reference, which isn't allowed per Rust's ownership rules.

I have also tried:

pub trait AsMut {
   fn as_mut(&mut self) -> &mut Self;
}

impl<T> AsMut for T {...}
impl<T> AsMut for &mut T {...}

But I get an error that says these implementations could possibly overlap

Generalizing over borrowed-or-not is possible, usually comes with complexity/lack of ergonomics/some other cost. Hard to suggest alternatives with the level of detail given though.


BorrowMut<T> is, but why wouldn't it work to just leave the bounds off and do

pub struct Foo<T> { field: T }
// ... use Foo<TheType> or Foo<&mut TheType> ...

Maybe you were looking for an enum. It's true you can't usefully hold a T and a &mut to that T in the same struct simultaneously. (The fields would alias and moves would immediately dangle.)


They definitely do, namely...

impl<T> AsMut for T {...}
impl<U> AsMut for &mut U {...}

...&'a mut U for any lifetime 'a is covered by the first implementation (let T = &'a mut U).

3 Likes

This topic was automatically closed 90 days after the last reply. We invite you to open a new topic if you have further questions or comments.