77 lines
3.0 KiB
Markdown
77 lines
3.0 KiB
Markdown
The `ImmutableString` Type
|
|
==========================
|
|
|
|
{{#include ../links.md}}
|
|
|
|
~~~admonish question.side "Why `SmartString`?"
|
|
|
|
[`SmartString`] is used because many strings in scripts are short (fewer than 24 ASCII characters).
|
|
~~~
|
|
|
|
All [strings] in Rhai are implemented as `ImmutableString`, which is an alias to
|
|
`Rc<SmartString>` (or `Arc<SmartString>` under the [`sync`] feature).
|
|
|
|
An `ImmutableString` is immutable (i.e. never changes) and therefore can be shared among many users.
|
|
Cloning an `ImmutableString` is cheap since it only copies an immutable reference.
|
|
|
|
Modifying an `ImmutableString` causes it first to be cloned, and then the modification made to the copy.
|
|
Therefore, direct string modifications are expensive.
|
|
|
|
|
|
Avoid `String` Parameters
|
|
-------------------------
|
|
|
|
`ImmutableString` should be used in place of `String` for function parameters because using `String`
|
|
is very inefficient (the argument is cloned during every function call).
|
|
|
|
A alternative is to use `&str` which de-sugars to `ImmutableString`.
|
|
|
|
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].
|
|
|
|
```rust
|
|
fn slow(s: String) -> i64 { ... } // string is cloned each call
|
|
|
|
fn fast1(s: ImmutableString) -> i64 { ... } // cloning 'ImmutableString' is cheap
|
|
|
|
fn fast2(s: &str) -> i64 { ... } // de-sugars to above
|
|
|
|
fn bad(s: &mut String) { ... } // '&mut String' will not match string values
|
|
```
|
|
|
|
|
|
Differences from Rust Strings
|
|
-----------------------------
|
|
|
|
Internally Rhai strings are stored as UTF-8 just like Rust (they _are_ Rust `String`s!),
|
|
but nevertheless there are major differences.
|
|
|
|
In Rhai a [string] is semantically the same as an array of Unicode characters and can be directly
|
|
indexed (unlike Rust).
|
|
|
|
This is similar to most other languages (e.g. JavaScript, C#) where strings are stored internally
|
|
not as UTF-8 but as arrays of UCS-16 or UCS-32.
|
|
|
|
Individual characters within a Rhai string can also be replaced just as if the string is an array of
|
|
Unicode characters.
|
|
|
|
In Rhai, there are also no separate concepts of `String` and `&str` (a string slice) as in Rust.
|
|
|
|
|
|
```admonish warning "Performance considerations"
|
|
|
|
Although Rhai exposes a [string] as a simple array of [characters] which can be directly indexed to
|
|
get at a particular [character], such convenient syntax is an _illusion_.
|
|
|
|
Internally the [string] is still stored in UTF-8 (native Rust `String`s).
|
|
|
|
All indexing operations actually require walking through the entire UTF-8 string to find the offset
|
|
of the particular [character] position, and therefore is _much_ slower than the simple array
|
|
indexing for other scripting languages.
|
|
|
|
This implementation detail is hidden from the user but has a performance implication.
|
|
|
|
Avoid large scale [character]-based processing of [strings]; instead, build an actual [array] of
|
|
[characters] (via the `split()` method) which can then be manipulated efficiently.
|
|
```
|