Syntax of matches! macro

Hi,

I am not really sure what the correct syntax of the matches! macro is. Say I have an enum like

enum Test {
    A {
        value: i32
    }
}

Now I know that I can match the values like following

let t = Test::A { value: 42 };
match t {
    Test::A { value } if value > 40 => {
        println!("Greater than 40");
     },
    Test::A { value } => {
        println!("{}", value);
    }
}

where the first guard could be asserted with

assert!(matches!(t, Test::A { value } if value > 40 ));

but can I also assert the second guard? Shouldn't this be possible?:

assert!(matches!(t, Test::A { value } => { ... }));

match expressions consider each pattern+guard in order. So the second match arm, Test::A { value } => { ... } is only reached if the first one fails to match. This means you could use something like

assert!(matches!(t, Test::A { value } if value <= 40 ));

in your example.


Note on terminology:

  • Test::A { value }” is a pattern,
  • if value > 40” is a guard (or match guard)
  • Test::A { value } if value > 40 => { println!("Greater than 40"); }” is a match arm
  • Test::A { value } => { println!("{}", value); }” is a match arm, too. This one does not contain a guard at all.

so

you might mean “the second match arm”, i.e. “can I also assert the second match arm is taken?”

Unless you mean something different.

1 Like

In general (as an approach that’s not specific to this example), you could assert the first pattern+guard does not match, and assert that the second one does match, something like

assert!(!(matches!(t, Test::A { value } if value > 40 )) && matches!(t, Test::A { value })

If, as is the case here, the second arm is also the last arm, so it’s just about not taking the first arm, then you can shorten it to

assert!(!(matches!(t, Test::A { value } if value > 40 )))

or

assert!(!matches!(t, Test::A { value } if value > 40 ))

(though some people find !matches! looks weird)

Wow, thanks for the insanely fast response.

Oh, ok so the macro expects guards but I'm providing a match arm.

assert!(matches!(t, Test::A { value } => { ... }));

Is there any way to test pseudo-code like this then in a clean way? I would like to test whether something is a specific enum variant and then further test the values this enum variant encloses.

assert!(matches!(t, Test::A {value} => {
    assert!(value > 40);
}));

I could of course do something like

if let Test::A { value } = foo() {
  assert!(value > 40);
}

but isn't there a cleaner way?


Edit: Sorry, the enclosed value is more complex than just an integer, so the simple if-guard won't do in this case, sadly.

Yes, the macro expects a pattern plus optionally a guard, so pretty much anthing that’s allowed on the left-hand-side of the => in a match arm.

Maybe it could help to post how the actual code you’re dealing with looks like then ^^

Yea, you're right, sorry ^^

I would like to write this test case in a cleaner way.

Especially parts like

...
if let Constant::Utf8 { tag: _, length: _, bytes } = constant {
    let s = str::from_utf8(bytes).unwrap();
    assert_eq!(s, "test");
    assert_eq!(f0.attributes_count, 1);
    
    let attribute = &f0.attributes[0];

    if let Attribute::ConstantValue { attribute_name_index: _, attribute_length: _, constantvalue_index } = attribute {

...

How about something like

assert!(matches!(
    constant,
    Constant::Utf8 {bytes, ..} if matches!(
        str::from_utf8(bytes),
        Ok("test"),
    ),
));
assert_eq!(f0.attributes_count, 1);
assert!(matches!(
    &f0.attributes[0],
    Attribute::ConstantValue {constantvalue_index, ..} if matches!(
        &constant_pool[(constantvalue_index - 1) as usize],
        Constant::Integer { value: 2147483647, .. },
    ),
));
1 Like

Ah yes, I think that would work. Thanks a lot!

And I guess sorry for the repost (in a way) :zipper_mouth_face:

actually.....

assert!(matches!(constant, Constant::Utf8 {bytes: b"test", ..}));

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.