traduccion ps4 lenguaje language descargar rust

rust - ps4 - Cómo hacer coincidir los ejecutores de rasgos



rust traduccion (2)

Tengo un rasgo que es implementado por algunas estructuras. Quiero escribir una coincidencia de patrón donde pueda manejar todos los casos posibles:

trait Base {} struct Foo { x: uint } struct Bar { y: uint } impl Base for Foo {} impl Base for Bar {} fn test(v: bool) -> Box<Base + ''static> { // Let''s pretend there''s real logic that determines what to return. if v { box Foo { x: 5 } } else { box Bar { y: 10 } } } fn main() { let f: Box<Base> = test(true); // Now that we have a `Box<Base>` (`*f` makes it a `Base`), // let''s handle different cases: match *f { Foo { x } => println!("it was Foo: {}!", x), Bar { y } => println!("it was Bar: {}!", y), } }

(pruébalo en línea: http://is.gd/YuBkPF )

Obtengo este error de compilación:

tipos no coincidentes: Base esperada, encontró un patrón de estructura


No puedes. Los rasgos no admiten downcasting - Rust no es un lenguaje basado en herencia / subtipificación, y le da otro conjunto de abstracciones. Además, lo que quiere hacer es incorrecto: los rasgos están abiertos (cualquiera puede implementarlos para cualquier cosa), por lo que incluso si en su caso, la match *f cubre todos los casos posibles, en general, el compilador no puede saberlo.

Tienes dos opciones aquí. Si conoce el conjunto de estructuras que implementan su rasgo de antemano, simplemente use enum, es una herramienta perfecta para esto. Le permiten emparejar estáticamente en un conjunto cerrado de variantes:

enum FooBar { Foo(uint), Bar(uint) } fn test(v: bool) -> FooBar { if v { Foo(5) } else { Bar(10) } } fn main() { let f: FooBar = test(true); // Now that we have a `Box<Base>` (`*f` makes it a `Base`), // let''s handle different cases: match f { Foo(x) => println!("it was Foo: {}!", x), Bar(y) => println!("it was Bar: {}!", y), } }

(inténtalo aquí )

Esta es, de lejos, la forma más simple y siempre debe ser preferida.

Otra forma es usar Any rasgo. Es una instalación para downcasting tipo seguro desde objetos de rasgo a tipos regulares:

use std::any::{Any, AnyRefExt}; struct Foo { x: uint } struct Bar { y: uint } fn test(v: bool) -> Box<Any + ''static> { // '' if v { box Foo { x: 5 } } else { box Bar { y: 10 } } } fn main() { let f: Box<Any> = test(true); match f.downcast_ref::<Foo>() { Some(&Foo { x }) => println!("it was Foo: {}!", x), None => match f.downcast_ref::<Bar>() { Some(&Bar { y }) => println!("it was Bar: {}!", y), None => unreachable!() } } // it will be nicer when `if let` lands // if let Some(&Foo { x }) = f.downcast_ref::<Foo>() { // println!("it was Foo: {}!", x); // } else if let Some(&Bar { y }) = f.downcast_ref::<Bar>() { // println!("it was Bar: {}!", y); // } else { unreachable!() } }

(inténtalo aquí )

Idealmente, debería ser posible escribir algo como esto:

trait Base : Any {} impl Base for Foo {} impl Base for Bar {}

y luego use Base en el código, pero no se puede hacer ahora porque la herencia de rasgos no funciona con objetos rasgo (por ejemplo, es imposible pasar de Box<Base> a Base<Any> ).


Puedes usar mi caja match_cast :

match_cast!( any { val as Option<u8> => { format!("Option<u8> = {:?}", val) }, val as String => { format!("String = {:?}", val) }, val as &''static str => { format!("&''static str = {:?}", val) }, }); match_down!( any { Bar { x } => { x }, Foo { x } => { x }, });