Match-statement to manipulate two variables at once?


I have a struct with two fields:

#[derive(Deserialize, Serialize)]
pub struct Voucher {
    distributorvoucher: Option<DistributorVoucher>,
    supervoucher_distributor: Option<Distributor>,


Either distributorvoucher or supervoucher_distributor has a value. Always exactly one of those field has a value, the other one is None.

I have written the following function to easily check if the Voucher is a 'supervoucher':

impl Voucher {
    fn is_supervoucher(&self) -> bool {

When inserting the Voucher into a database I need to know which field to insert a NULL.

I can successfully do it this way:

let distributorvoucher_id = match &voucher.is_supervoucher() {
        true => Some(voucher.distributorvoucher.as_ref().unwrap().id),
        false => None,
    let supervoucher_distributor = match &voucher.is_supervoucher() {
        true => Some(voucher.supervoucher_distributor.as_ref().unwrap().id),
        false => None,

However, I was wondering if there is a shorter solution. I fabricated the following which seems to work:

let (distributorvoucher_id, supervoucher_distributor) = match &voucher.is_supervoucher() {
        true => (Some(voucher.distributorvoucher.as_ref().unwrap().id), None),
        false => (

I am, however, not sure this is valid code. Is this the right way to do it? Thanks!

The shortest way would be to use Option::map():

let distributorvoucher_id = voucher.distributorvoucher.as_ref().map(|dv|;
let supervoucher_distributor = voucher.supervoucher_distributor.as_ref().map(|svd|;

A longer way would be to explicitly match on the two fields:

let distributorvoucher_id = match &voucher.distributorvoucher {
    Some(dv) => Some(,
    None => None,
let supervoucher_distributor = match &voucher.supervoucher_distributor {
    Some(svd) => Some(,
    None => None,

Or to assert that exactly one has a value:

let (distributorvoucher_id, supervoucher_distributor) = match (
) {
    (Some(dv), None) => (Some(, None),
    (None, Some(svd)) => (None, Some(,
    _ => unreachable!(),
1 Like

If feasible, I would replace the two fields with an enum.

enum SomeName {

impl SomeName {
    fn id(&self) -> u64 {
        match self {
            SomeName::Distribution(d) =>,
            SomeName::Super(s) =>,

    fn is_supervoucher(&self) -> bool {
        matches!(self, SomeName::Super(_))

    // ...

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.