Is there a way to not hand the instance of a parent struct to a child struct if I want to change the field in an instance of a child struct, later used by another child instance?

Below is my real-life example just a tad simplified.
I've got the structs:

  • App,
  • (AppChild)Box,
  • (BoxChild)Text

and App has the field address that I want to hand over to the AddressBox,
where a user will enter it's address, thus I want it stored in the App address field.
(I'm not sure if I'm using the right terminology here.)

The address: (&*self.address).to_string(), part of the
code is simply me building on top of the solution from my last question.
I know it won't hand over the field, but I'm clueless as to what the best solution is.
I can hand over an instance of a username field
from AddressBox to AddressText just fine,
but since AddressBox has the line:
self.address = input_text;
in it. It can't hand down field names from Parent to Child the same way.

So my question is,
is there a way not to hand over the entire parent instance
for this type of Parent-Child relationship as well?

use std::fmt;

const DEFAULT_ADDRESS: &str = "1 Main Street";

enum Page {
    NoBoxFound, Escape, 
    MainMenu, PhoneNumber
}

#[allow(dead_code)]
enum Choice {
    Yes, No, Cancel, Escape,
}

struct _App {
    username: String,
    address: String,
    phone_number: String,
}

impl _App {
    // ...
    fn _get_address_page(&self) -> AddressBox {
        AddressBox {
            address: (&*self.address).to_string(),
            username: &*self.username,
        }
    }
    //...
}

trait PageHandler {
    fn get_text(&self) -> String;
    fn handle(&mut self) -> Page;
}

struct AddressBox<'a> {
    pub address: String,
    pub username: &'a str,
}

impl PageHandler for AddressBox<'_> {
    fn handle(&mut self) -> Page {
        match PageBox::choice(self.get_text(), 
        DEFAULT_ADDRESS) {
            (Choice::Yes, Some(input_text)) => {
                self.address = input_text;
                Page::PhoneNumber
            },
            (Choice::Escape, _) => Page::Escape,
            (Choice::Cancel, _) => Page::MainMenu,
            _ => Page::NoBoxFound,
        }
    }
    
    fn get_text(&self) -> String {
        AddressText {
            username: &*self.username,
        }.to_string()
    }
}

struct AddressText<'a> {
    username: &'a str,
}

impl fmt::Display for AddressText<'_> {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        writeln!(f, "Please type in the address for {}:", self.username)
    }
}

struct PageBox {}

impl PageBox {
    fn choice(_text: String, _input: &str) -> (Choice, Option<String>) {
        (Choice::Yes, Some("1 Main Street".to_string()))
    }
}

(Playground)

I don't fully understand your question, but is Rc<RefCell<T>> the solution? The Rc<...> part allows you to .clone() the thingy, so you can have it accessible in multiple places. The RefCell<...> part allows you to .borrow_mut() and modify it.

1 Like

I'll simplify it again:

use std::fmt;

fn main() {
   let p :Parent = Parent { 
       field_one: String::from("one"), 
       field_two: String::from("two"),
   };
   p.get_child().method();
   
   assert_eq!(p.get_child().get_child(), "blah blah two\n");
   assert_eq!(p.field_one, "blah blah one\n");
}

struct Parent {
    field_one: String,
    field_two: String,
}

impl Parent {
    fn get_child(&self) -> Child {
        Child {
            field_one: (&*self.field_one).to_string(),
            field_two: &*self.field_two,
        }
    }
}

struct Child<'a> {
  field_one: String,
  field_two: &'a str,
}

impl Child<'_> {
   fn method(&mut self) {
        self.field_one = String::from("blah blah one\n");
   }

  fn get_child(&self) -> String {
        GrandChild {
            field: &*self.field_two,
        }.to_string()
    }
}

struct GrandChild<'a> {
   field: &'a str,
}


impl fmt::Display for GrandChild<'_> {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        writeln!(f, "blah blah {}", self.field)
    }
}

Playground

Is there a reason &mut can't work for your use case?

struct AddressBox<'a> {
    pub address: &'a mut String,
    pub username: &'a str,
}

impl PageHandler for AddressBox<'_> {
    fn handle(&mut self) -> Page {
        match PageBox::choice(self.get_text(), DEFAULT_ADDRESS) {
            (Choice::Yes, Some(input_text)) => {
                *self.address = input_text;
                Page::PhoneNumber
            }
1 Like

Ah, I keep confusing mutability for ownership.

1 Like

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.