How to construct struct B<'a> { ref_item: &'a A, item: Option<A>, }

Hello,

Newbie question: How do I correctly implement B::from_A?

struct A;

struct B<'a> {
    ref_item: &'a A,
    item: Option<A>,
}

impl<'a> B<'a> {/*
    fn from_A(a: A) -> B {
        B {
            ref_item: &a,
            item: a,
        }
    }*/
    
    fn from_ref_A(a: &'a A) -> B<'a> {
        B {
            ref_item: &a,
            item: None,
        }
    }
}


fn build_A() -> Result<A, B<'static>> {
    let a = A {};
    Ok(a)
    //Err(B::from_A(a))
}

impl A {
    fn foo(&self) -> Result<(), B> {
        Err(B::from_ref_A(self))
    }
}

You can't create self-referential structs in safe Rust. If a field pointed to another field, then moving the struct would cause the reference to be dangling.

There is almost always a better way to do what you want to achieve. What are you actually trying to do?

1 Like

B is an error type for various methods of A, which requires a ref to the A instance. I am trying to deal with the case where an error occurs before the instance is actually assigned to a variable . i.e. in build_A

That is not clear. Please show actual code.

It looks like you're trying to recreate Cow... You don't need to store an internal reference to A if you already own an A, as you can always create the reference as needed by borrowing from the owned one.

3 Likes

That is exactly what I was trying to do. Thanks

Actually, Cow is not exactly what I was trying to do as I do not want to make A cloneable. However, looking at Cow suggests to me this solution:

use core::ops::Deref;

struct A;

enum AorAref<'a> {
    Borrowed(&'a A),
    Owned(A),
}

impl Deref for AorAref<'_> {
    type Target = A;

    fn deref(&self) -> &A {
        match *self {
            AorAref::Borrowed(a) => a,
            AorAref::Owned(ref a) => a,
        }
    }
}


struct B<'a> {    
    item: AorAref<'a>,
}

impl<'a> B<'a> {
    fn from_A(a: A) -> B<'static> {
        B { item: AorAref::Owned(a) }
    }
    
    fn from_ref_A(a: &'a A) -> B<'a> {
        B { item: AorAref::Borrowed(a) }
    }
}

Is this a reasonable/idiomatic implementation? Am I still trying to re-invent the wheel?

That depends on what you're actually trying to accomplish. Most of the time, your code will be much simpler if you give up trying to abstract over different kinds of ownership and just choose to always own or always borrow. Without knowing what you're trying to do, it's hard to suggest a better way to do it.

1 Like

I am trying to create an error type that I can use in a Result<A, AError>. AError needs to be able to call some of A's methods.

My understanding is that if I pass an owned A to AError, in

if let Err(e) = a.do_something() {
    // deal with error
} ...
a.do_something_else()

a will be invalid at the call do_something_else. On the other hand, if I pass a borrowed copy

let a = create_an_a(); 
if let Err(e) = a { 
    // deal with error during A creation
} ...

will not work because in the Err case because the new A instance will not outlive the body of the create_an_a function.

Is my understanding correct?

(a fuller listing of what I am trying to do is given below)


use core::ops::Deref;

enum AorAref<'a> {
    Borrowed(&'a A),
    Owned(A),
}

impl Deref for AorAref<'_> {
    type Target = A;

    fn deref(&self) -> &A {
        match *self {
            AorAref::Borrowed(a) => a,
            AorAref::Owned(ref a) => a,
        }
    }
}

struct AError<'a> {
    a: AorAref<'a>,
}

impl<'a> AError<'a> {
    fn handle_error(self) {
        println!("{:?}", self.a.i)
    }
}

struct ABuilder {
    a: A,
}

impl ABuilder {
    fn start() -> Self {
        Self { a: A { i: 42 } }
    }

    fn build(self, ok: bool) -> Result<A, AError<'static>> {
        if ok {
            Ok(self.a)
        } else {
            Err(AError {
                a: AorAref::Owned(self.a),
            })
        }
    }
}

pub struct A {
    i: i32,
}

impl A {
    fn do_something(&self, ok: bool) -> Result<(), AError> {
        if ok {
            Ok(())
        } else {
            Err(AError {
                a: AorAref::Borrowed(self),
            })
        }
    }
}

fn main() {
    let a = ABuilder::start().build(false);
    if let Err(e) = a {
        e.handle_error()
    };
    let b = ABuilder::start().build(true);
    if let Ok(ref a) = b {
        let e = a.do_something(false);
        if let Err(e) = e {
            e.handle_error()
        };
    }
}

From what I can see, you should just make AError own the A. Then write

fn do_something(self, ok: bool) -> Result<Self, AError>

And if the call fails, give the A back via AError. Either way, there's no reason to borrow it here, because the user already has access to it. (Or perhaps you should store an Option<A> in AError, and just store None when you call do_something...) In fact, the Option will probably just be better represented as a custom enum, and you can capture the A for a build error, and don't capture it for a do_something error.

But you should probably not be trying to access A from within the AError generally. (It will certainty be a bad idea if you end trying to call mutating methods on it while it's still borrowed for the function call.)

Here's one way to do it: playground link.

1 Like