Dynamic Values

A Dynamic value can be any type, as long as it implements Clone.

Send + Sync

Under the sync feature, all types must also be Send + Sync.

let x = 42;         // value is an integer

x = 123.456;        // value is now a floating-point number

x = "hello";        // value is now a string

x = x.len > 0;      // value is now a boolean

x = [x];            // value is now an array

x = #{x: x};        // value is now an object map

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)}`)
}

Type Checking and Casting

Tip: Dynamic::try_cast

The try_cast method does not panic but returns None upon failure.

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

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

Use clone_cast to clone a reference to Dynamic.

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.

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" => ...
        :
}

Always full path name

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_boolboolbool
from_intINTinteger number
from_floatno_floatFLOATfloating-point number
from_decimalnon-decimalDecimalDecimal
from_str&strstring
from_charcharcharacter
from_arrayno_indexVec<T>array
from_blobno_indexVec<u8>BLOB
from_mapno_objectMapobject map
from_timestampno_stdstd::time::Instant (instant::Instant if WASM build)timestamp
from<T>Tcustom type

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<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>
into_blobno_indexResult<Blob, &str>
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<()>()
From<INT>integer number
From<FLOAT>no_floatfloating-point number
From<Decimal>non-decimalDecimal
From<bool>bool
From<S: Into<ImmutableString>>
e.g. From<String>, From<&str>
ImmutableString
From<char>character
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<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<Instant>no_stdtimestamp
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