Mitchell Ingram
Mitchell Ingram

Reputation: 706

Pattern matching inside of struct

I want to use a pattern match to check the inside of a struct without building a new struct. I am trying to swap value of the struct as an exercise (I know mem::swap exists).

Swapping means matching a value of the struct and then swapping the matching values. Like let x = {10,20,30}; x.swap(10,30) should yield {30,20,10}.

What I want to be able to, but can't

#[derive(Debug, Clone, Copy)]
struct Color {
    r: u8,
    g: u8,
    b: u8,
    a: u8,
}

impl Color {
    fn swap(mut self, first: u8, second: u8) -> Color {
        match (first) {
            self.r => {
                match (second) {
                    self.b => {
                        self.r = second;
                        self.b = first;
                    },
                    self.g => {
                        self.r = second;
                        self.g = first;
                    },
                    self.a => {
                        self.r = second;
                        self.a = first;
                    },
                    _ => {},
                }
            },
            _ => {}
        }

        Color {
            r: self.r,
            g: self.g,
            b: self.b,
            a: self.a,
        }
    }
}
fn main() {
    let c = Color {
        r: 255,
        g: 200,
        b: 10,
        a: 30,
    };

    let color = c.swap(c.r, c.a);

    println!("{:?}", color);
}

The code is not valid, it is what I would like to accomplish. Is there a way to do this? I assume I am way off base on this approach.

Upvotes: 3

Views: 1765

Answers (1)

Shepmaster
Shepmaster

Reputation: 430320

Technically, there is a way to do this with pattern matching, but you'd likely never see this in practice. The missing piece is to use a match guard:

match first {
    v if v == self.r => {
        match second {
            v if v == self.b => {
                self.r = second;
                self.b = first;
            },
            v if v == self.g => {
                self.r = second;
                self.g = first;
            },
            v if v == self.a => {
                self.r = second;
                self.a = first;
            },
            _ => {},
        }
    },
    _ => {}
}

But this isn't really using any useful part of pattern matching; it's just a bunch of if else clauses:

if first == self.r {
    if second == self.b {
        self.r = second;
        self.b = first;
    } else if second == self.g {
        self.r = second;
        self.g = first;
    } else if second == self.a {
        self.r = second;
        self.a = first;
    }
}

You could choose to shoehorn in some patterns though:

let x1 = (first == self.r, first == self.g, first == self.b, first == self.a);
let x2 = (second == self.r, second == self.g, second == self.b, second == self.a);

match (x1, x2) {
    ((true, _, _, _), (_, true, _, _)) => {
        self.r = second;
        self.b = first;
        }
    ((true, _, _, _), (_, _, true, _)) => {
        self.r = second;
        self.g = first;
        }
    ((true, _, _, _), (_, _, _, true)) => {
        self.r = second;
        self.a = first;
    }
    _ => {}
}

Upvotes: 2

Related Questions