Dynamic Values

A Dynamic value can be any type. However, under sync, all types must be Send + Sync.

Use type_of() to Get Value Type

Because type_of() a Dynamic value returns the type of the actual value, it is usually used to perform type-specific actions based on the actual value’s type.

let mystery = get_some_dynamic_value();

switch type_of(mystery) {
    "i64" => print("Hey, I got an integer here!"),
    "f64" => print("Hey, I got a float here!"),
    "string" => print("Hey, I got a string here!"),
    "bool" => print("Hey, I got a boolean here!"),
    "array" => print("Hey, I got an array here!"),
    "map" => print("Hey, I got an object map here!"),
    "Fn" => print("Hey, I got a function pointer here!"),
    "TestStruct" => print("Hey, I got the TestStruct custom type here!"),
    _ => print("I don't know what this is: " + type_of(mystery))
}

Functions Returning Dynamic

In Rust, sometimes a Dynamic forms part of a returned value – a good example is an array which contains Dynamic elements, or an object map which contains Dynamic property values.

To get the real values, the actual value types must be known in advance. There is no easy way for Rust to decide, at run-time, what type the Dynamic value is (short of using the type_name function and match against the name).

Type Checking and Casting

A Dynamic value’s actual type can be checked via the is method.

The cast method then converts the value into a specific, known type.

Alternatively, use the try_cast method which does not panic but returns None when the cast fails.


#![allow(unused)]
fn main() {
let list: Array = engine.eval("...")?;      // return type is 'Array'
let item = list[0];                         // an element in an 'Array' is 'Dynamic'

item.is::<i64>() == true;                   // 'is' returns whether a 'Dynamic' value is of a particular type

let value = item.cast::<i64>();             // if the element is 'i64', this succeeds; otherwise it panics
let value: i64 = item.cast();               // type can also be inferred

let value = item.try_cast::<i64>()?;        // 'try_cast' does not panic when the cast fails, but returns 'None'
}

Type Name

The type_name method gets the name of the actual type as a static string slice, which can be match-ed against.


#![allow(unused)]
fn main() {
let list: Array = engine.eval("...")?;      // return type is 'Array'
let item = list[0];                         // an element in an 'Array' is 'Dynamic'

match item.type_name() {                    // 'type_name' returns the name of the actual Rust type
    "i64" => ...
    "alloc::string::String" => ...
    "bool" => ...
    "crate::path::to::module::TestStruct" => ...
}
}

Note: type_name always returns the full Rust path name of the type, even when the type has been registered with a friendly name via Engine::register_type_with_name. This behavior is different from that of the type_of function in Rhai.

Conversion Traits

The following conversion traits are implemented for Dynamic:

  • From<i64> (i32 if only_i32)
  • From<f64> (if not no_float)
  • From<bool>
  • From<rhai::ImmutableString>
  • From<String>
  • From<char>
  • From<Vec<T>> (into an array)
  • From<HashMap<String, T>> (into an object map)
  • From<Instant> (into a timestamp if not no_std)