匹配内部可变枚举的预期方法是什么?

What is the intended way to match an interior mutable enum?

这些是我可以想出的方法来尝试匹配引用计数的内部可变枚举:

#![allow(unused)]

use std::cell::RefCell;
use std::rc::Rc;

#[derive(Debug, Clone, PartialEq)]
struct Bar {
    some_bar: Vec<f64>,
}
#[derive(Debug, Clone, PartialEq)]
struct Baz {
    some_baz: i32,
}

#[derive(Debug, Clone, PartialEq)]
enum Foo {
    Bar(Bar),
    Baz(Baz),
}

fn is_baz(foo_ref: Rc<RefCell<Foo>>) -> bool {
    match foo_ref {
        Foo::Bar(_) => false,
        Foo::Baz(_) => true,
    }
}

fn is_baz_borrow(foo_ref: Rc<RefCell<Foo>>) -> bool {
    match foo_ref.borrow() {
        Foo::Bar(_) => false,
        Foo::Baz(_) => true,
    }
}

fn is_baz_deref(foo_ref: Rc<RefCell<Foo>>) -> bool {
    match *foo_ref {
        Foo::Bar(_) => false,
        Foo::Baz(_) => true,
    }
}

fn is_baz_get_mut(foo_ref: Rc<RefCell<Foo>>) -> bool {
    match foo_ref.get_mut() {
        Foo::Bar(_) => false,
        Foo::Baz(_) => true,
    }
}

fn is_baz_as_ref(foo_ref: Rc<RefCell<Foo>>) -> bool {
    match foo_ref.as_ref() {
        Foo::Bar(_) => false,
        Foo::Baz(_) => true,
    }
}

fn is_baz_as_ref_borrow(foo_ref: Rc<RefCell<Foo>>) -> bool {
    match foo_ref.as_ref().borrow() {
        Foo::Bar(_) => false,
        Foo::Baz(_) => true,
    }
}

fn is_baz_get_mut_mut(mut foo_ref: Rc<RefCell<Foo>>) -> bool {
    match foo_ref.get_mut() {
        Foo::Bar(_) => false,
        Foo::Baz(_) => true,
    }
}

fn main() {
    let foo = Foo::Bar(Bar {
        some_bar: vec![1.1, 999.0],
    });
    let foo_ref = Rc::new(RefCell::new(foo));

    // none of these work
    assert!(is_baz(foo_ref.clone()));
    assert!(is_baz_borrow(foo_ref.clone()));
    assert!(is_baz_deref(foo_ref.clone()));
    assert!(is_baz_get_mut(foo_ref.clone()));
    assert!(is_baz_as_ref(foo_ref.clone()));
    assert!(is_baz_as_ref_borrow(foo_ref.clone()));

    // this works
    assert!(is_baz_get_mut_mut(foo_ref.clone()));
}

Playground

然而,大多数方法都会产生类型不匹配的错误,例如

error[E0308]: mismatched types
  --> src/main.rs:24:9
   |
24 |         Foo::Baz(_) => true
   |         ^^^^^^^^^^^ expected struct `std::rc::Rc`, found enum `Foo`
   |
   = note: expected type `std::rc::Rc<std::cell::RefCell<Foo>>`
              found type `Foo`

error[E0308]: mismatched types
  --> src/main.rs:30:9
   |
30 |         Foo::Bar(_) => false,
   |         ^^^^^^^^^^^ expected struct `std::cell::Ref`, found enum `Foo`
   |
   = note: expected type `std::cell::Ref<'_, Foo, >`
              found type `Foo`

唯一可行的方法是:

match foo_ref.get_mut() {
    Foo::Bar(_) => false,
    Foo::Baz(_) => true
}

这是预期的方式吗?即使是只读访问?

您可以使用 RefDeref 实现:

fn is_baz_get(foo_ref: Rc<RefCell<Foo>>) -> bool {
    match *foo_ref.borrow() {
        Foo::Bar(_) => false,
        Foo::Baz(_) => true
    }
}