为什么联合上的模式匹配具有无法访问的模式警告?

Ehs*_*ani 2 pattern-matching rust

鉴于文档,我无法理解为什么联合上的模式匹配不能正常工作:

union A {
    a1: i32,
    a2: f32,
}

struct B(A);
let b = B(A { a2: 1.0 });
unsafe {
    match b.0 {
        A { a1 } => println!("int"),
        A { a2 } => println!("float"),
    }
}
Run Code Online (Sandbox Code Playgroud)

输出带有无法访问警告的"int".

warning: unreachable pattern
  --> src/main.rs:12:13
   |
12 |             A { a2 } => println!("float"),
   |             ^^^^^^^^
   |
   = note: #[warn(unreachable_patterns)] on by default
Run Code Online (Sandbox Code Playgroud)

She*_*ter 5

a的全部意义union在于编译器不会在union它的类型中存储任何信息; 这完全取决于程序员.因此,没有用于match确定值的类型的信息.

因此,您的代码在概念上等同于

struct A {
    a1: i32,
}

let b = A { a1: 42 };

match b {
    A { a1 } => println!("int {}", a1),
    A { a1 } => println!("float {}", a1),
}
Run Code Online (Sandbox Code Playgroud)

在任何情况下都不会执行第二个匹配臂.

事实上,在字段之间来回切换是一个主要用途union:

union A {
    i: i32,
    f: f32,
}

let a = A { i: 42 };
let b = unsafe { a.f };

println!("{}", b);
Run Code Online (Sandbox Code Playgroud)

enum如果您希望编译器跟踪您拥有的变体,您可能希望使用.在某些情况下,枚举被称为标记联合,因为它正是它们的原样:带有标记的并集以识别联合包含的内容.

否则,您需要以其他方式跟踪联合中实际的类型.一种方法是实现自己的标记:

union A {
    a1: i32,
    a2: f32,
}

struct B {
    is_int: bool,
    data: A,
}

let b = B {
    is_int: false,
    data: A { a2: 1.0 },
};

unsafe {
    match b {
        B {
            is_int: true,
            data: A { a1 },
        } => println!("int {}", a1),
        B {
            is_int: false,
            data: A { a2 },
        } => println!("float {}", a2),
    }
}
Run Code Online (Sandbox Code Playgroud)

标签可以是您可以匹配的任何内容:

union A {
    a1: i32,
    a2: f32,
}

struct B {
    kind: Kind,
    data: A,
}

enum Kind {
    Int,
    Float,
}

let b = B {
    kind: Kind::Float,
    data: A { a2: 1.0 },
};

unsafe {
    match b {
        B {
            kind: Kind::Int,
            data: A { a1 },
        } => println!("int {}", a1),
        B {
            kind: Kind::Float,
            data: A { a2 },
        } => println!("float {}", a2),
    }
}
Run Code Online (Sandbox Code Playgroud)

我想你甚至可以用一个枚举各地工会...

union A {
    a1: i32,
    a2: f32,
}

enum B {
    Int(A),
    Float(A),
}

let b = B::Float(A { a2: 1.0 });

unsafe {
    match b {
        B::Int(A { a1 }) => println!("int {}", a1),
        B::Float(A { a2 }) => println!("float {}", a2),
    }
}
Run Code Online (Sandbox Code Playgroud)

  • @ EhsanM.Kermani如果你有**100种可能性的联盟**你有更大的问题.无论如何,我仍然*说静态地执行更多的事情会更好.如果这不是你的目标,那么Rust*可能*不适合你或你试图解决的问题. (3认同)
  • @ EhsanM.Kermani另外,如果你有一个具有相同类型的两种可能性的联合,那么似乎'TypeId`将无法使用. (3认同)