如何在 Rust 中访问复杂枚举类型的元素?

3
例如,考虑以下内容:
#[deriving(Eq, Show)]
struct EventOne {
  x: f64,
  y: f64
}

#[deriving(Eq, Show)]
struct EventTwo {
  x: int,
  y: int
}

#[deriving(Eq, Show)]
enum ComplexEvent {
  A(EventOne, ~str),
  B(EventTwo, ~str)
}

我这里有一个复杂的枚举类型 ComplexEvent,它可以是 A 或者 B。

我希望能够做到以下操作:

let x = A(EventOne { x: 0.1, y: 0.1}, ~"Hello");
let z = x.EventOne;

...但这会导致错误:

error: attempted access of field `EventOne` on type `union::ComplexEvent`, but no field with that name was found
let z = x.EventOne;

嗯...好的,作为一个数组?

error: cannot index a value of type `union::ComplexEvent`
let z = x[0];

好的,为了保证类型安全,您可能需要使用match来实现这个功能?

match x {
  A(_, _) => ???,
  B(_, _) => ???
}

...

union.rs:28:3: 31:4 error: mismatched types: expected `()` but found `std::result::Result<(),std::io::IoError>` (expected () but found enum std::result::Result)
union.rs:28   match x {
union.rs:29     A(_, _) => ???,
union.rs:30     B(_, _) => ???
union.rs:31   }
error: aborting due to previous error

我可能只是缺少让这个工作所需的具体语法,但我无论如何都想不出来......

编辑:从示例中删除 => 操作,因为它似乎让每个人都感到困惑。看问题啊!我想要从已经存在的枚举类型中获取一个子值,而不是匹配(match())枚举类型并执行println!

4个回答

5
相当简单:
let x = A(EventOne { x: 0.1, y: 0.1 }, ~"Hello");
match x {
    A(EventOne{x, y}, s) => println!("{}, {}, {}", x, y, s),
    B(EventTwo{x, y}, s) => println!("{}, {}, {}", x, y, s)
}

注意,这样匹配意味着你正在移出`~str`字段,因为它不是隐式可复制的,所以`x`成为部分移动值,你不能再进一步使用。如果确实想在匹配后使用该值,可以通过引用绑定`s`:
let x = B(EventTwo { x: 1, y: 2 }, ~"World");
match x {
    A(EventOne{x, y}, ref s) => println!("{}, {}, {}", x, y, *s),
    B(EventTwo{x, y}, ref s) => println!("{}, {}, {}", x, y, *s)
}

在这种情况下,s 的类型为&~str,因此您需要对其进行取消引用以打印它。之后您将能够使用x,因为您没有将~str字段移出,并且另一个字段是隐式可复制的,因为它由隐式可复制的数据组成。

+1 我只会将初始的 x 变量名更改为 z,这样就不会被同名的内部变量隐藏,以使事情更加清晰明了。 - oblitum
@pepper_chico,你说得对,不过我注意到在Rust中覆盖外部作用域的变量是惯用法。x不应该在匹配分支内使用,所以将其保留不变是安全的。 - Vladimir Matveev

0

如果有更好的解决方案,我会接受它,但是实现这个的方法是:

macro_rules! trace(
  ($($arg:tt)*) => (
    { ::std::io::stdout().write_line(format_args!(::std::fmt::format, $($arg)*)); }
  );
)

#[deriving(Eq, Show)]
struct EventOne {
  x: f64,
  y: f64
}

#[deriving(Eq, Show)]
struct EventTwo {
  x: int,
  y: int
}

#[deriving(Eq, Show)]
enum ComplexEvent {
  A(EventOne, ~str),
  B(EventTwo, ~str)
}

#[test]
fn test_lifetime_scope() {
  let x = A(EventOne { x: 0.1, y: 0.1}, ~"Hello");
  let y = B(EventTwo { x: 1, y: 2}, ~"Hello2");
  let mut z:&EventOne = &EventOne { x: 0.0, y: 0.0 };

  match x {
    A(ref a, _) => z = a,
    B(b, _) => trace!("{}", b)
  }

  trace!("Accessed values: {}", z);
}

0

你需要像最后一个例子中那样使用match。你在那里得到的错误是由于使用了trace!()(这是什么?我的Rust没有它),它的返回类型是IoResult<()>(这是Result<(),std::io::IoError>的typedef),但Rust希望你的表达式具有类型()


0
use std::rand;
use std::rand::Rng;

#[deriving(Eq, Show)]
struct EventOne {
    x: f64,
    y: f64
}

#[deriving(Eq, Show)]
struct EventTwo {
    x: int,
    y: int
}

#[deriving(Eq, Show)]
enum ComplexEvent {
    A(EventOne, ~str),
    B(EventTwo, ~str)
}

#[deriving(Eq, Show)]
enum Event { EventOne, EventTwo }

fn main() {
    let mut rng = rand::rng();

    let z:ComplexEvent =
        if rng.gen() {
            A(EventOne { x: 0.1, y: 0.1 }, ~"☺")
        } else {
            B(EventTwo { x: 100, y: 200 }, ~"☹")
        };

    match z {
        A(e, _) => println!("{}", e),
        B(e, _) => println!("{}", e)
    }
}

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接