-1

How do I match on an enum reference? I am using a dependency that returns a reference to an enum and I need to read the value the enum contains. In the following example, the thing I care about is assigning final_val with x:

fn main() {
    let test_string = String::from("test");
    let option: std::option::Option<String> = Some(test_string);
    let ref_option = &option;

    let final_val = match ref_option {
        Some(x) => x,
        _ => String::from("not Set"),
    };

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

If I follow what the compiler suggests and add a & to the type Some and ref x:

fn main() {
    let test_string = String::from("test");
    let option: std::option::Option<String> = Some(test_string);
    let ref_option = &option;

    let final_val = match ref_option {
        &Some(ref x) => x,
        _ => String::from("not Set"),
    };

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

I get the following error, which I don't know how to resolve:

error[E0308]: match arms have incompatible types
  --> src\main.rs:6:21
   |
6  |       let final_val = match ref_option
   |  _____________________^
7  | |     {
8  | |         &Some(ref x) => x,
9  | |         _ => String::from("not Set" ),
   | |              ------------------------ match arm with an incompatible type

10 | |     };
   | |_____^ expected reference, found struct `std::string::String`
   |
   = note: expected type `&std::string::String`
              found type `std::string::String`
Shepmaster
  • 388,571
  • 95
  • 1,107
  • 1,366
ZNackasha
  • 755
  • 2
  • 9
  • 29
  • Do you want the type of `final_val` to be a string, or a reference to a string? You can't do both. – loganfsmyth Mar 23 '18 at 02:48
  • I would like it to be a string – ZNackasha Mar 23 '18 at 03:41
  • In case the enum is *actually* an `&Option`, then check out [Why does Option.as_ref() not deref to Option<&str>?](https://stackoverflow.com/q/44163624/155423) and [Converting from Option to Option<&str>](https://stackoverflow.com/q/31233938/155423). TL;DR: `ref_option.as_ref().map_or("not Set", String::as_str)`. – Shepmaster Mar 23 '18 at 14:25

2 Answers2

6

This does not work. On the first arm you return &String, in the second arm you return String.

It will work if you clone x, but it's unclear what you really want.

let final_val = match ref_option {
    &Some(ref x) => x.clone(),
    _ => String::from("not Set"),
};

Playground

Edit:

I would like it to be a string

Then the mentioned solution is the way to go. However, if you don't really need a String, you should go with tafia's solution:

let final_val = match *ref_option {
    Some(ref x) => x,
    _ => "not Set",
};

Playground

Tim Diekmann
  • 7,755
  • 11
  • 41
  • 69
2

There are 2 issues

  1. You must either match on *ref_option or have &Some(...) and &None in the branches. Matching on *ref_option is more idiomatic.

  2. Once matched, you use a ref x which is a reference to the String (equivalent to a &String). So either you clone it, as suggested by Tim or you return a &String (dereferenced to a &str) in both branches.

To conclude, you can:

let final_val = match *ref_option {
    Some(ref x) => x,
    _ => "not Set",
};
Shepmaster
  • 388,571
  • 95
  • 1,107
  • 1,366
tafia
  • 1,512
  • 9
  • 18