Help with ownership a tuple inside match

Hi. I want to change the value of the fields in a struct. Every field is passing to a vector (in a tuple), and every tuple is passing in an iteractor. I'm messing up with the borrow system in rust, and I'm stuck.

struct Colors {
    bg: u32,
    fg: u32,
    font: u32,
}

impl Default for Colors {
    fn default() -> Self {
        Colors {
            bg: 0x0,
            fg: 0xffffff,
            font: 0xff0000,
        }
    }
}

//A more complex function that read from files,
//but for this sample always returns "ff00ff"
fn get_color(_color_name: String) -> String {
    "ff00ff".to_string()
}

fn main() {
    let mut colors = Colors::default(); // Compiler warning variable does not need to be mutable
a
    let colors_tuple = vec![
        ("background", &colors.bg),
        ("foreground", &colors.fg),
        ("font", &colors.font),
    ];

    for &(mut tuple) in colors_tuple.iter() {
        let hex_string = get_color(tuple.0.to_string());

        match u32::from_str_radix(&hex_string, 32) {
            Ok(v) => tuple.1 = &v, // How can I change colors.xxx value?
            Err(_e) => panic!("BAD HEX NUMBER!"),
        }
    }
    println!("background: {}", colors.bg); //Writes 0. must be 0xff00ff
}
warning: variable does not need to be mutable
  --> src\main.rs:24:9
   |
24 |     let mut colors = Colors::default(); // Compiler warning variable does not need to be mutable
   |         ----^^^^^^
   |         |
   |         help: remove this `mut`
   |
   = note: `#[warn(unused_mut)]` on by default

On the other hand, using references I can’t make it to work (same compiler warning):

    let colors_tuple = vec![
        ("background", &colors.bg),
        ("foreground", &colors.fg),
        ("font", &colors.font),
    ];

    for &(mut tuple) in colors_tuple.iter() {
        let hex_string = get_color(tuple.0.to_string());

        match u32::from_str_radix(&hex_string, 32) {
            Ok(v) => tuple.1 = &v, // How can I change colors.xxx value?
            Err(_e) => panic!("BAD HEX NUMBER!"),
        }
    }

Any help will be appreciated.

The problem is that you don't change the values of the colors struct, but the references the tuples you use to access the fields of colors point to. I've made minimal changes to your snippet in order to make it work:

struct Colors {
    bg: u32,
    fg: u32,
    font: u32,
}

impl Default for Colors {
    fn default() -> Self {
        Colors {
            bg: 0x0,
            fg: 0xffffff,
            font: 0xff0000,
        }
    }
}

//A more complex function that read from files,
//but for this sample always returns "ff00ff"
fn get_color(_color_name: String) -> String {
    "ff00ff".to_string()
}

fn main() {
    let mut colors = Colors::default(); // Compiler warning variable does not need to be mutable
    
    let mut colors_tuple = vec![
        ("background", &mut colors.bg),
        ("foreground", &mut colors.fg),
        ("font", &mut colors.font),
    ];

    for tuple in colors_tuple.iter_mut() {
        let hex_string = get_color(tuple.0.to_string());

        match u32::from_str_radix(&hex_string, 32) {
            Ok(v) => *tuple.1 = v, 
            Err(_e) => panic!("BAD HEX NUMBER!"),
        }
    }
    println!("background: {}", colors.bg); //Writes 0. must be 0xff00ff
}

Here a link to the playground.

First, I made the references in the tuples at the second position mutable, so that we are able to change the value at this address. Also, note the change in line 36:

to:

Ok(v) => *tuple.1 = v

Instead of changing the reference the pointer at tuple position two points to, I dereference the pointer (* before the pointer) and change the underlying value, pointing to the colors struct.
Otherwise I had to change the mutability of the the tuple vector to satisfy rust's mutability guarantees (e.g. you can't hide mutable references inside immutable references). You can find an excellent introduction to referencing in rust in the rust book.

1 Like

Thank you so much!!!.

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.