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!"),
    "decimal" => print("Hey, I got a decimal 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.

Use clone_cast for on a reference to Dynamic.


#![allow(unused)]
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

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.

Methods and Traits

The following methods are available when working with Dynamic:

MethodNot available underReturn typeDescription
from<T> (instance method)Dynamiccreate a Dynamic from any value that implements Clone
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

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)
try_cast<T>Option<T>
clone_cast<T>cloned copy of T (panics on failure)
as_unitResult<(), &str>
as_intResult<i64, &str>
as_int (only_i32)Result<i32, &str>
as_floatno_floatResult<f64, &str>
as_float (f32_float)no_floatResult<f32, &str>
as_decimalnon-decimalResult<Decimal, &str>
as_boolResult<bool, &str>
as_charResult<char, &str>
take_stringResult<String, &str>
take_immutable_stringResult<ImmutableString, &str>

Constructor traits

The following constructor traits are implemented for Dynamic:

TraitNot available underData type
From<i64>i64
From<i32> (only_i32)i32
From<f64>no_floatf64
From<f32> (f32_float)no_floatf32
From<Decimal>non-decimalDecimal
From<bool>bool
From<S: Into<ImmutableString>>
e.g. From<String>, From<&str>
ImmutableString
From<char>char
From<Vec<T>>no_indexarray
From<&[T]>no_indexarray
From<BTreeMap<K: Into<SmartString>, T>>
e.g. From<BTreeMap<String, T>>
no_objectobject map
From<HashMap<K: Into<SmartString>, T>>
e.g. From<HashMap<String, T>>
no_object or no_stdobject map
From<FnPtr>function pointer
From<Instant>no_stdtimestamp
From<Rc<RefCell<Dynamic>>>sync or no_closureDynamic
From<Arc<RwLock<Dynamic>>> (sync)non-sync or no_closureDynamic