admin管理员组

文章数量:1294739

Can we have initializers in the match expression just like C++ if statement with initializers if statement initializers. The reason I'm asking is because the below code is resulting in deadlock and I thought of resolving this deadlock issue using initializers like the commented code below.

use std::sync::{Arc, Mutex};

struct A {
    id: u32,
    is_ok: bool,    
}

impl A {
    fn new(id: u32) -> Self {
        Self {
            id,
            is_ok: false,
        }
    }
}

fn main() {
    let ar = Arc::new(Mutex::new(A::new(1)));
    
    // match (a = &ar.lock().unwrap(); a.is_ok) {
    match ar.lock().unwrap().is_ok {
        true => {},
        false => println!("{}", ar.lock().unwrap().id),
        // false => println!("{}", a.id),
    };
}

Can we have initializers in the match expression just like C++ if statement with initializers if statement initializers. The reason I'm asking is because the below code is resulting in deadlock and I thought of resolving this deadlock issue using initializers like the commented code below.

use std::sync::{Arc, Mutex};

struct A {
    id: u32,
    is_ok: bool,    
}

impl A {
    fn new(id: u32) -> Self {
        Self {
            id,
            is_ok: false,
        }
    }
}

fn main() {
    let ar = Arc::new(Mutex::new(A::new(1)));
    
    // match (a = &ar.lock().unwrap(); a.is_ok) {
    match ar.lock().unwrap().is_ok {
        true => {},
        false => println!("{}", ar.lock().unwrap().id),
        // false => println!("{}", a.id),
    };
}
Share Improve this question edited Feb 12 at 11:40 Harry asked Feb 12 at 11:07 HarryHarry 3,0761 gold badge24 silver badges46 bronze badges 0
Add a comment  | 

3 Answers 3

Reset to default 1

The simplest way is to lock once, match on the result and move your condition into a guard:

    match ar.lock().unwrap() {
        a if a.is_ok => {}
        a => println!("{}", a.id),
    }

You can get sort of close with #![feature(let_chains)] in edition 2024, though a would only be available in the true case:

    if let a = ar.lock().unwrap()
        && a.is_ok
    {
    } else {
        println!("{}", ar.lock().unwrap().id);
    }

But it's not idiomatic and requires you to reaquire the lock in the else case, and locking twice for a single data access would be quite problematic, it opens the door for time-of-check to time-of-use errors. Even then the compiler warns about the irrefutable pattern, it recommends to just put the assignment before the if.

Something close and would work in this case is a block expression:

match { let a = &ar.lock().unwrap(); a.is_ok } {
    true => {},
    false => println!("{}", ar.lock().unwrap().id),
};

However, it does not have the same semantics as a C++ initializer - any variables introduced in the block are only accessible within that block and are not accessible in the control flow body.

A better way to handle this is via if let statement like below

if let Ok(a) = ar.lock() {
    match a.is_ok {
        true => {},
        false => println!("{}", a.id),
    }
};

本文标签: rustmatch expression with initializersStack Overflow