Custom Type Property Getters and Setters

A custom type can also expose properties by registering get and/or set functions.

Properties can be accessed in a JavaScript-like syntax:

object . property

object . property = value ;

Getters and setters each take a &mut reference to the first parameter.

Getters and setters are disabled when the no_object feature is used.

Engine APIFunction signature(s)
(T: Clone = custom type,
V: Clone = data type)
Can mutate T?
register_getFn(&mut T) -> Vyes, but not advised
register_setFn(&mut T, V)yes
register_get_setgetter: Fn(&mut T) -> V
setter: Fn(&mut T, V)
yes, but not advised in getter
register_get_resultFn(&mut T) -> Result<V, Box<EvalAltResult>>yes, but not advised
register_set_resultFn(&mut T, V) -> Result<(), Box<EvalAltResult>>yes

By convention, property getters are not supposed to mutate the custom type, although there is nothing that prevents this mutation.

Cannot Override Object Maps

Property getters and setters are mainly intended for custom types.

Any getter or setter function registered for object maps is simply ignored because the get/set calls will be interpreted as properties on the object maps.

Examples


#![allow(unused)]
fn main() {
#[derive(Debug, Clone)]
struct TestStruct {
    field: String
}

impl TestStruct {
    // Remember &mut must be used even for getters
    fn get_field(&mut self) -> String {
        self.field.clone()
    }

    fn set_field(&mut self, new_val: &str) {
        self.field = new_val.to_string();
    }

    fn new() -> Self {
        Self { field: "hello" }
    }
}

let mut engine = Engine::new();

engine.register_type::<TestStruct>()
      .register_get_set("xyz", TestStruct::get_field, TestStruct::set_field)
      .register_fn("new_ts", TestStruct::new);

let result = engine.eval::<String>(r#"
                let a = new_ts();
                a.xyz = "42";
                a.xyz
             "#)?;

println!("Answer: {}", result);                     // prints 42
}

IMPORTANT: Rhai does NOT support normal references (i.e. &T) as parameters.

Fallback to Indexer

If the getter/setter of a particular property is not defined, but an indexer is defined on the custom type with string index, then the corresponding indexer will be called with the name of the property as the index value.

In other words, indexers act as a fallback to property getters/setters.


#![allow(unused)]
fn main() {
a.foo           // if property getter for 'foo' doesn't exist...

a["foo"]        // an indexer (if any) is tried
}