11

It seems as though you can't. If not, is there any planned support to add it or run-time type information (RTTI)?

struct Bus;
struct Car;
struct Person;

fn main() {
    let x = Bus;
    //or more realistically, let x = function_with_multiple_return_types();

    match x {
        Car => {
            // ...
        }
        Bus => {
            // this gets executed
        }
        Person => {
            // ...
        }
    }
}

This example is trivial. In real life, it would only be useful if x could be multiple types. e.g. let x = function_with_multiple_return_types();.

Shepmaster
  • 388,571
  • 95
  • 1,107
  • 1,366
randyrand
  • 433
  • 1
  • 4
  • 9
  • Idk Rust, but I would expect that each clause of the match would need to be of the same type. Try making them all part of the same superclass / interface – Carcigenicate Nov 10 '16 at 23:06
  • The closest thing you can get may be a tagged union such as the example [here](https://doc.rust-lang.org/book/enums.html). – squiguy Nov 10 '16 at 23:28

2 Answers2

9

No one can say with 100% accuracy that a feature will or won't ever be implemented, but I can say with 100% belief that this will never be implemented.

Why is that? Because there's zero benefit to the proposed syntax. Rust is a statically-typed language. That means that the compiler knows what the type of a variable is. There's no way that any branch besides Bus would ever be executed. There's no way that a variable can have more than one type! Why would the language change to allow you to add code that could never be used? That wouldn't be very useful.

A match statement, and pattern matching in general, is really only useful when there are multiple possible variants of something. That's why Rust has enums; to allow a fixed set of dynamic choices (a.k.a. made at runtime).

If you need an open set of dynamic decisions, that's what traits (and maybe specialization) are for. There's even a trait that allows for any concrete type.


As mentioned in the comments, you can use trait object downcasting which is provided by Any, but there's no ability to use match.

See also:

Shepmaster
  • 388,571
  • 95
  • 1,107
  • 1,366
  • My question was inspired from a Racket interpreter I wrote where Match could branch on different types. Lisp is of course dynamically typed, though, so it makes sense in Rust this is not typically useful. I feel there there could be niche cases where having a function return types dynamically could be useful (though not idomatic) - std::any seems to mostly cover this use case though. Thanks! – randyrand Nov 11 '16 at 00:28
  • 1
    Lisp being dynamically typed is where my initial confusion came from. – randyrand Nov 11 '16 at 00:37
  • *return types dynamically* — but even then you want to *do* something with those returned types. That means there is a set of methods that you want to be able to call; that's what a trait implies. It can be returned as a trait object. – Shepmaster Nov 11 '16 at 00:49
  • @Shepmaster What if the match goes over a reference, a trait implementation, trying to downcast it (`let x: &Display = ...; match x {&String => ...}`), and happens some place where the compiler doesn't know the exact type? Wouldn't that be useful? – ArtemGr Nov 11 '16 at 18:22
  • @ArtemGr it does know the exact type — `&Display` ;-) It sounds like you are asking about *trait object downcasting* (see [1](http://stackoverflow.com/q/25246443/155423), [2](http://stackoverflow.com/q/27892375/155423)), which is provided by `Any`. There's no ability to `match` though, as `match` would need to statically know all the possibilities, as I understand it. – Shepmaster Nov 11 '16 at 18:27
  • @Shepmaster I knows about anys and it's not very ergonomics, don't you sees? And wouldn't blanks (`_`) save the match from needsing to know too much? – ArtemGr Nov 11 '16 at 18:30
  • There's even a room to implement something like the Scala typeful Duck Typing, methinks. Wich is a different route from downcasting but interesting nevertheless. – ArtemGr Nov 11 '16 at 18:32
  • The issue is the compiler may know the exact type, but the user does not know it / has no way to express it when using a macro. As a macro can return any type and macro's can't do any sort of type-checking, the only way to check would be with conditions that are being resolved by the compiler. – Luxalpa Dec 05 '21 at 15:56
1

Check out std::any::Any and Andrew Johnson's link. I think you will be able to do something close to what you wanted to do using Any. fn get_type_id(&self) -> TypeId is only in the nightly builds though, so if you have the stable version of Rust you may be unable to use it yet.

This example is close to what you want, just with if let instead of match.

I wrote three examples to demonstrate how you might accomplish this, Although none are usable with match sadly... They can be found be found and run here. The following is my favorite way of doing it:

fn run_example_one() {
    let unknown_type = gen_rand_any();

    if let Some(string) = unknown_type.downcast_ref::<String>() {
       println!("It's a string!");
    } else if let Some(my_struct) = unknown_type.downcast_ref::<MyStruct>() {
        println!("my struct! name = {:?}", my_struct.my_name);
    } else if let Some(int) = unknown_type.downcast_ref::<i32>() {
       println!("something singed 32 bit int.");
   }
}
Shepmaster
  • 388,571
  • 95
  • 1,107
  • 1,366
Marek Counts
  • 126
  • 3
  • 11