Cannot compile code when use struct value inside match arm

I got an error when try to compile code below:

error: expected one of `!`, `(`, `...`, `..=`, `..`, `::`, `=>`, `if`, `{`, or `|`, found `.`
  --> src/main.rs:21:32
   |
21 |         Opcode::LOGIN_CHALLENGE.value => true,
   |                                ^ expected one of 10 possible tokens

error: could not compile `playground` due to previous error
#[derive(Debug)]
pub struct OpcodeField {
    pub name: String,
    pub value: u32,
}

#[non_exhaustive]
pub struct Opcode;

#[allow(dead_code)]
impl Opcode {
    pub const LOGIN_CHALLENGE: OpcodeField = OpcodeField {
        name: String::from("LOGIN_CHALLENGE"),
        value: 100,
    };
}

fn main() {
    let opcode: u32 = 100;
    let result = match opcode {
        Opcode::LOGIN_CHALLENGE.value => true,
        _ => false,
    };
}

Link to sandbox

Could somebody explain how to fix ?

UPDATED: btw, when I try to move Opcode::LOGIN_CHALLENGE.value into variable, I got another error:

error[E0015]: cannot call non-const fn `<String as From<&str>>::from` in constants
  --> src/main.rs:13:15
   |
13 |         name: String::from("LOGIN_CHALLENGE"),
   |               ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
   |
   = note: calls in constants are limited to constant functions, tuple structs and tuple variants

Link to reproduce

It's unclear to me what exactly you're trying to do with the match, but it is somewhat irrelevant: you can't create a const with a non-empty String because allocation is not a compile-time operation. That's what your latter error is getting at.

The reason this is an error is because the only values that you can use in a pattern (such as the left side of a match arm) to compare against are literals and const items. Option::LOGIN_CHALLENCE is the path (name) of a const item, but .value is not. You cannot use the dot operator in patterns in any way.

You could, however, declare a new const to extract the value:

    let opcode: u32 = 100;
    const LOGIN_CHALLENGE_VALUE: u32 = Opcode::LOGIN_CHALLENGE.value;
    let result = match opcode {
        LOGIN_CHALLENGE_VALUE => true,
        _ => false,
    };

Future versions of Rust may allow this to be written as an “inline const” so that you would be able to write

        const { Opcode::LOGIN_CHALLENGE.value } => true,

but for now your only option is the named const.

1 Like

#[derive(Debug)]
pub struct OpcodeField {
pub name: String,
pub value: u32,
}

#[non_exhaustive]
pub struct Opcode;

#[allow(dead_code)]
impl Opcode {
pub const LOGIN_CHALLENGE: OpcodeField = OpcodeField {
name:String::new(),
value: 100,
};
}

use std::any::type_name;

fn type_of(_: T) -> &'static str {
type_name::()
}

fn main() {

let opcode: u32 = 100;

let result = match type_of(opcode) == type_of(Opcode::LOGIN_CHALLENGE.value) {
true => true,
_ => false,

};

print!("type {} == type const {} ? {} ", type_of(opcode), type_of(Opcode::LOGIN_CHALLENGE.value), result);
}

I got another simpler solution:

let result = match opcode {
        _ if Opcode::LOGIN_CHALLENGE.value == opcode => true,
        _ => false,
    };

it can work with any amount of opcodes within match. The only issue I have for now is error with String:

error[E0015]: cannot call non-const fn `<String as From<&str>>::from` in constants
  --> src/main.rs:13:15
   |
13 |         name: String::from("LOGIN_CHALLENGE"),
   |               ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
   |
   = note: calls in constants are limited to constant functions, tuple structs and tuple variants
#[derive(Debug)]
pub struct OpcodeField<'a> {
pub name: &'a str,
pub value: u32,
}

#[non_exhaustive]
pub struct Opcode;

#[allow(dead_code)]
impl Opcode {
pub const LOGIN_CHALLENGE: OpcodeField<'_> = OpcodeField {
name: "LOGIN_CHALLENGE",
value: 100,
};
}

use std::any::type_name;

fn type_of<T>(_: T) -> &'static str {
type_name::<T>()
}

fn main() {

let opcode: u16= 110;

let result = match opcode {
_ if type_of(Opcode::LOGIN_CHALLENGE.value) == type_of(opcode) => true,
_ => false,
};

print!("type {} == type const {} ? {} name={}", type_of(opcode), type_of(Opcode::LOGIN_CHALLENGE.value), result, Opcode::LOGIN_CHALLENGE.name);
}

could you format your code with pair of triple slash quote ? ```

ok done

It seems to me that you are not really using pattern matching to any benefit here. Why not just

let result = if Opcode::LOGIN_CHALLENGE.value == opcode { true }
             else if Opcode::BLOGGING_CHALLENGE.value == opcode { true || false }
             else { false };

which repeats opcode one time less?

1 Like

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.