String
Parameters in Rust Functions
As much as possible, avoid using String
parameters in functions.
Each String
argument is cloned during every single call to that function –
and the copy immediately thrown away right after the call.
Needless to say, it is extremely inefficient to use String
parameters.
&str
Maps to ImmutableString
A common mistake made by novice Rhai users is to register functions with String
parameters.
Rust functions accepting parameters of String
should use &str
instead because it maps directly
to ImmutableString
which is the type that Rhai uses to represent strings internally.
The parameter type String
involves always converting an ImmutableString
into a String
which mandates cloning it.
Using ImmutableString
or &str
is much more efficient.
fn get_len1(s: String) -> i64 { // BAD!!! Very inefficient!!!
s.len() as i64
}
fn get_len2(s: &str) -> i64 { // this is better
s.len() as i64
}
fn get_len3(s: ImmutableString) -> i64 { // the above is equivalent to this
s.len() as i64
}
engine.register_fn("len1", get_len1)
.register_fn("len2", get_len2)
.register_fn("len3", get_len3);
let len = engine.eval::<i64>("len1(x)")?; // 'x' cloned, very inefficient!!!
let len = engine.eval::<i64>("len2(x)")?; // 'x' is shared
let len = engine.eval::<i64>("len3(x)")?; // 'x' is shared
A function with the first parameter being &mut String
does not match a string argument passed to it,
which has type ImmutableString
.
In fact, &mut String
is treated as an opaque custom type.
fn bad(s: &mut String) { ... } // '&mut String' will not match string values
fn good(s: &mut ImmutableString) { ... }
engine.register_fn("bad", bad)
.register_fn("good", good);
engine.eval(r#"bad("hello")"#)?; // <- error: function 'bad (string)' not found
engine.eval(r#"good("hello")"#)?; // <- this one works