Pregunta

For example, consider:

#[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)
}

I have here a complex enum ComplexEvent that can be either an A, or a B.

I would like to be able to do something like this:

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

...but that results in the error:

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

Erm... ok, as an array?

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

Ok, well to be type safe maybe you need to use match for this?

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

I'm probably just missing the specific syntax you need to get this working, but I can't for the life of me figure it out...

Edit: Removing the => action on the example because it seems to be confusing everyone. Read the question guys! I want to get a subvalue from inside an enum that already exists, not match() an enum and do a println!

¿Fue útil?

Solución

Pretty simple:

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)
}

Note that matching like this means that you are moving out ~str field because it is not implicitly copyable, so x becomes partially moved value, which you cannot use further. If you do want to use the value after the match, you can bind s by reference:

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)
}

In this case s has type &~str, so you have to dereference it to print it. You will be able to use x afterwards, because you are not moving ~str field out, and the other field is implicitly copyable because it consists of implicitly copyable data.

Otros consejos

You need to use a match, as you did in your final example. The error you got there is due to the use of trace!() (what is that? My Rust doesn't have it), which has the return type IoResult<()> (which is a typedef for Result<(),std::io::IoError>), but Rust was expecting your expression to have the type ().

I'll accept another better solution if one comes up, but the way to do this is:

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);
}
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)
    }
}
Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top