4

Can the following C# code be translated to Rust?

dynamic x = 109;
x = "Hi";

I'm asking for a general dynamic type to allow creating an array of dynamic values. For example:

var l = new dynamic[2];
l[0] = 102;
l[1] = "Hi";
Shepmaster
  • 388,571
  • 95
  • 1,107
  • 1,366
TuxCrafting
  • 299
  • 3
  • 11
  • Your edit would make this a duplicate of [What is the best way to create a heterogeneous collection of objects?](http://stackoverflow.com/questions/27957103/what-is-the-best-way-to-create-a-heterogeneous-collection-of-objects). – Shepmaster Jul 05 '16 at 18:58
  • Do you actually need to allow any type, or just a closed union of types (e.g. `int` or `string`)? – Lee Jul 05 '16 at 19:03

2 Answers2

4

One option is to use a vector of Any (link to beta because the stable docs is not showing the methods defined for Any, but they are stable):

use std::any::Any;

fn main() {
    let mut v: Vec<Box<Any>> = vec![];
    v.push(Box::new(102usize));
    v.push(Box::new("Hi"));

    for item in &v {
        // to do an operation, it is necessary to downcast to
        // a concrete type
        if let Some(x) = item.downcast_ref::<usize>() {
            println!("num = {:?}", x)
        }
    }
}

Note that, contrary to dynamic in C#, that is assumed to support any operation, a value of type Any (Box<Any>) only support the operations defined in Any (Box<Any> and Any). A downcast is necessary to call any method of the concrete type.


I think that it is not possible to have a type like dynamic of C# in Rust. To support calling any method on a dynamic value, it is necessary to have (complete) runtime reflection support, and Rust does not provide it.

If you know the methods that will be called, then the best option is to define a trait and use Box<Trait> (Any is not necessary in this case).

Matthieu M.
  • 287,565
  • 48
  • 449
  • 722
malbarbo
  • 10,717
  • 1
  • 42
  • 57
  • Ah, I was just about to update with this. Note that you cannot downcast to a trait object, so you cannot get "any type that is printable", for example. Still doesn't match `dynamic` because you can't just call any arbitrary method. – Shepmaster Jul 05 '16 at 19:38
3

Not directly. You can just create a new binding for x:

fn main() {
    let x = 109;
    let x = "Hi";
}

Depending on your use case, you might be able to use a generic bounded by a trait or a trait object to achieve similar goals:

use std::fmt::Display;

fn main() {
    let mut x: Box<Display> = Box::new(109);
    x = Box::new("Hi");
}

However, the C# docs state:

At compile time, an element that is typed as dynamic is assumed to support any operation.

This is not true for a trait object; a trait object only can be used for the explicit methods in the trait. I have not found this to be a significant hurdle in the code I have written. Generally, there's a fixed number of methods that I want to call so it's possible to map those to a trait. In other cases, I can provide a generic type to allow the user to specify a type that fits their case.

Shepmaster
  • 388,571
  • 95
  • 1,107
  • 1,366