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) {
    "()" => print("Hey, I got the unit () here!"),
    "i64" => print("Hey, I got an integer here!"),
    "f64" => print("Hey, I got a float here!"),
    "decimal" => print("Hey, I got a decimal here!"),
    "range" => print("Hey, I got an exclusive range here!"),
    "range=" => print("Hey, I got an inclusive range 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!"),
    "blob" => print("Hey, I got a BLOB here!"),
    "map" => print("Hey, I got an object map here!"),
    "Fn" => print("Hey, I got a function pointer here!"),
    "timestamp" => print("Hey, I got a time-stamp 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 Dynamic::is.

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.

Use clone_cast for on a reference to Dynamic.

fn main() {
let list: Array = engine.eval("...")?;      // return type is 'Array'
let item = list[0].clone();                 // 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'

let value = list[0].clone_cast::<i64>();    // use 'clone_cast' on '&Dynamic'
let value: i64 = list[0].clone_cast();

Type Name and Matching Types

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

This is a very simple and direct way to act on a Dynamic value based on the actual type of the data value.

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" => ...
    "f64" => ...
    "rust_decimal::Decimal" => ...
    "core::ops::range::Range<i64>" => ...
    "core::ops::range::RangeInclusive<i64>" => ...
    "alloc::string::String" => ...
    "bool" => ...
    "char" => ...
    "rhai::FnPtr" => ...
    "std::time::Instant" => ...
    "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.

Methods and Traits

The following methods are available when working with Dynamic:

MethodNot available underReturn typeDescription
type_name&strname of the value’s type
into_sharedno_closureDynamicturn the value into a shared value
flatten_cloneDynamicclone the value (a shared value, if any, is cloned into a separate copy)
flattenDynamicclone the value into a separate copy if it is shared and there are multiple outstanding references, otherwise shared values are turned unshared
read_lock<T>no_closure (pass thru’)Option< guard to T>lock the value for reading
write_lock<T>no_closure (pass thru’)Option< guard to T>lock the value exclusively for writing

Constructor instance methods

MethodNot available underValue typeData type
from_intINTinteger number
from_floatno_floatFLOATfloating-point number
from_mapno_objectMapobject map
(instant::Instant if WASM build)

Detection methods

MethodNot available underReturn typeDescription
is<T>boolis the value of type T?
is_variantboolis the value a trait object (i.e. not one of Rhai’s standard types)?
is_read_onlyboolis the value constant? A constant value should not be modified.
is_sharedno_closureboolis the value shared via a closure?
is_lockedno_closureboolis the value shared and locked (i.e. currently being read)?

Casting methods

The following methods cast a Dynamic into a specific type:

MethodNot available underReturn type (error is the actual data type)
cast<T>T (panics on failure)
clone_cast<T>cloned copy of T (panics on failure)
as_unitResult<(), &str>
as_intResult<INT, &str>
as_floatno_floatResult<FLOAT, &str>
as_decimalnon-decimalResult<Decimal, &str>
as_boolResult<bool, &str>
as_charResult<char, &str>
into_stringResult<String, &str>
into_immutable_stringResult<ImmutableString, &str>
into_arrayno_indexResult<Array, &str>array
into_blobno_indexResult<Blob, &str>array
into_typed_array<T>no_indexResult<Vec<T>, &str>

Constructor traits

The following constructor traits are implemented for Dynamic where T: Clone:

TraitNot available underData type
From<INT>integer number
From<FLOAT>no_floatfloating-point number
From<S: Into<ImmutableString>>
e.g. From<String>, From<&str>
From<BTreeMap<K: Into<SmartString>, T>>
e.g. From<BTreeMap<String, T>>
no_objectobject map
From<BTreeSet<K: Into<SmartString>>>
e.g. From<BTreeSet<String>>
no_objectobject map
From<HashMap<K: Into<SmartString>, T>>
e.g. From<HashMap<String, T>>
no_object or no_stdobject map
From<HashSet<K: Into<SmartString>>>
e.g. From<HashSet<String>>
no_object or no_stdobject map
From<FnPtr>function pointer
From<Rc<RefCell<Dynamic>>>sync or no_closureDynamic
From<Arc<RwLock<Dynamic>>> (sync)non-sync or no_closureDynamic
FromIterator<X: IntoIterator<Item=T>>no_indexarray