String value into enum

Hello,
Today I have encountered following problem. I am given an csv file and for each of it's elements I would like to initialize my struct:

#[derive(Debug)]
enum Directions {
  RIGHT,
  LEFT,
  UP,
  DOWN,
}

#[derive(Debug)]
struct Move {
  pub direction: Directions,
  pub value: i32,
}

Code which is supposed to do that looks like that:

pub fn draw_wire(wire_moves: &str) -> () {
    let moves: Vec<Move> = wire_moves
      .split(",")
      .into_iter()
      .map(|move_elem|
        Move {
          direction: match move_elem[..0] {
            "R" => Directions::RIGHT,
            "L" => Directions::LEFT,
            "U" => Directions::UP,
            "D" => Directions::DOWN,
            _ => panic!("Invalid move direction!")
          },
          value: move_elem[1..].parse::<i32>().unwrap()
        }
      )
      .collect();

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

So basically, what I am trying to do here is to return correct enum value based on first character of each element. The problem is, that currently I am getting following error:

error[E0308]: mismatched types
  --> src/main.rs:39:28
   |
39 |           direction: match move_elem[..0] {
   |                            ^^^^^^^^^^^^^^ expected &str, found str
   |
   = note: expected type `&str`
              found type `str`

Could you please help me with that? What is the real problem here?

Regards!

If you add a &, i.e. match &move_elem[ , does it fix it?

In addition to this, using .chars().next() would be preferred to avoid potential panics.

The .into_iter() is also throwing me off. I often see types &str and String, but seeing str is new ot me.

In this case it did compile, but panic error was thrown which means that match didn't work. Do you have any idea why could that be?

Do you have some better idea of solving that? Anything really would be valuable for me as I am completely rust newbie (as you could probably already have noticed see)

Can you change

_ => panic!("Invalid move direction!")

to

x => {
  println!("got unexpected: |{:?}|", x);
  panic!();
}

The point here is that we have no idea what it is trying to match against. The above code is so that (1) we capture the string, (2) print it out, and (3) panic afterwards.

The {:?} is to print the variable in debug mode (i.e. derive Debug).

The |{:?}| is to add two || bars incase there are spaces in the string.

Also, is your intention to:

(1) trying to match the string vs "R", "L", "U", "D" or

(2) to match the FIRST LETTER vs 'R', 'L', 'U', 'D'

?

I have modified it a little:

pub fn draw_wire(wire_moves: &str) -> () {
    println!("Before: {:?}", wire_moves);
    let moves: Vec<Move> = wire_moves
      .split(",")
      .map(|move_elem|
        Move {
          direction: match &move_elem[..0] {
            "R" => Directions::RIGHT,
            "L" => Directions::LEFT,
            "U" => Directions::UP,
            "D" => Directions::DOWN,
            x => {
              println!("got unexpected: |{:?}|", x);
              panic!();
            }
          },
          value: move_elem[1..].parse::<i32>().unwrap()
        }
      )
      .collect();

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

And got following output:

Before: "R1005,U370,L335,D670,R236,D634,L914,U15,R292,D695,L345,D183,R655,U438,R203,U551,L540,U51,R834,D563,L882,D605,L832,U663,R899,D775,L740,U764,L810,U442,R379,D951,L821,D703,R526,D624,L100,D796,R375,U129,L957,D41,R361,D504,R358,D320,L392,D842,R509,D612,L92,U788,L361,D757,R428,U257,L663,U956,L748,U938,R588,D942,R819,D732,R562,D331,L164,U801,R872,U872,L909,U260,R899,D278,R822,U968,L937,D594,L786,D34,R102,D650,R920,D539,R925,U436,R347,U686,L596,D608,R730,U5,R462,U831,R277,U411,R730,D828,L169,D276,L669,U167,R55,D879,L329,U258,R585,D134,R977,D609,L126,U848,L601,U624,R577,D421,L880,D488,R505,U385,L103,D693,L110,D338,R809,D864,L80,U413,R412,D134,L519,D988,R83,U580,R593,U435,R843,D953,R11,D655,R569,D237,R987,U894,L445,U974,L746,U450,R99,U69,R84,U258,L248,D581,R215,U306,R480,U126,R275,D353,R493,D800,L386,D876,L957,D722,L967,D612,L716,D901,R394,U764,R274,D686,L746,D957,R747,U517,L575,D961,R842,D753,L345,D59,L215,U413,R610,D166,L646,U107,L926,D848,R445,U297,L376,U869,L345,D529,R620,D353,R682,D908,R378,D221,R64,D911,L245,D364,R123,D555,L928,U412,R771,D543,L97,D477,R500,D125,R578,U150,R291,D252,R948,D576,L838,D144,L289,D677,L307,U692,R802,D743,R57,U839,R896,D110,R34,D508,L595,U658,L769,U47,L292,U66,R217,D8,L835,D479,L71,D24,R429,U64,R305,D406,R23,U819,R478,D7,L561,D503,R349,U104,L749,D123,R548,D421,R336,D837,R464,D908,L94,U988,L137,D757,L42,U842,R260,D406,L31,U965,L178,U973,L29,U276,L887,U920,L133,U243,R537,U282,R194,D152,R693,D509,L771,D365,L319,D378,L61,D849,R379"
got unexpected: |""|
thread 'main' panicked at 'explicit panic', src/main.rs:46:15

My input always has following pattern {DIRECTION}{VALUE} -> where DIRECTION is always single char. I want to map following input to struct attached in description in which first letter is mapped to corresponding enum value and value for that is also attached.

I think the easiest fix is to change:

match &move_elem[..0] {
            "R" => Directions::RIGHT,
            "L" => Directions::LEFT,
            "U" => Directions::UP,
            "D" => Directions::DOWN,
            x => {
              println!("got unexpected: |{:?}|", x);
              panic!();
            }
          },

to

match move_elem[0] {
            'R' => Directions::RIGHT,
            'L' => Directions::LEFT,
            'U' => Directions::UP,
            'D' => Directions::DOWN,
            x => {
              println!("got unexpected: |{:?}|", x);
              panic!();
            }
          },

The point here is (1) we are matching vs first char of the string and (2) we change "R" to 'R' to indicate we want the char rather than the string of length 1.

Ranges are inclusive..exclusive so ..0usize is always empty.

4 Likes

@leudz 's observation is spot on. An even easier fix would be to change

to &move_elem[..1]

Unfortunatelly it didn't work. Solution was to fix it with:

direction: match &move_elem[..1] {
            "R" => Directions::RIGHT,
            "L" => Directions::LEFT,
            "U" => Directions::UP,
            "D" => Directions::DOWN,
            x => {
              println!("got unexpected: |{:?}|", x);
              panic!();
            }
          },

Seems like stupid mistake... thank you for help!