Refine string docs.

This commit is contained in:
Stephen Chung 2020-07-22 21:32:56 +08:00
parent abf66850f6
commit e103c8e66c
4 changed files with 33 additions and 21 deletions

View File

@ -20,9 +20,14 @@ The `ImmutableString` Type
------------------------- -------------------------
All strings in Rhai are implemented as `ImmutableString` (see [standard types]). All strings in Rhai are implemented as `ImmutableString` (see [standard types]).
An `ImmutableString` does not change and can be shared.
`ImmutableString` should be used in place of the standard Rust type `String` when registering functions Modifying an `ImmutableString` causes it first to be cloned, and then the modification made to the copy.
because using `String` is very inefficient (the `String` must always be cloned).
### **IMPORTANT** - Avoid `String` Parameters
`ImmutableString` should be used in place of `String` for function parameters because using
`String` is very inefficient (the `String` argument is cloned during every call).
A alternative is to use `&str` which maps straight to `ImmutableString`. A alternative is to use `&str` which maps straight to `ImmutableString`.
@ -67,14 +72,6 @@ Individual characters within a Rhai string can also be replaced just as if the s
In Rhai, there are also no separate concepts of `String` and `&str` as in Rust. In Rhai, there are also no separate concepts of `String` and `&str` as in Rust.
Immutable Strings
----------------
Rhai use _immutable_ strings (type `ImmutableString`) and can be shared.
Modifying a Rhai string actually causes it first to be cloned, and then the modification made to the copy.
Examples Examples
-------- --------

View File

@ -14,7 +14,7 @@ The following primitive types are supported natively:
| **Immutable Unicode [string]** | `rhai::ImmutableString` (implemented as `Rc<String>` or `Arc<String>`) | `"string"` | `"hello"` etc. | | **Immutable Unicode [string]** | `rhai::ImmutableString` (implemented as `Rc<String>` or `Arc<String>`) | `"string"` | `"hello"` etc. |
| **[`Array`]** (disabled with [`no_index`]) | `rhai::Array` | `"array"` | `"[ ?, ?, ? ]"` | | **[`Array`]** (disabled with [`no_index`]) | `rhai::Array` | `"array"` | `"[ ?, ?, ? ]"` |
| **[Object map]** (disabled with [`no_object`]) | `rhai::Map` | `"map"` | `"#{ "a": 1, "b": 2 }"` | | **[Object map]** (disabled with [`no_object`]) | `rhai::Map` | `"map"` | `"#{ "a": 1, "b": 2 }"` |
| **[Timestamp]** (implemented in the [`BasicTimePackage`][packages], disabled with [`no_std`]) | `std::time::Instant` ([`instant::Instant`] if not [WASM] build) | `"timestamp"` | _not supported_ | | **[Timestamp]** (implemented in the [`BasicTimePackage`][packages], disabled with [`no_std`]) | `std::time::Instant` ([`instant::Instant`] if [WASM] build) | `"timestamp"` | _not supported_ |
| **[Function pointer]** | `rhai::FnPtr` | `Fn` | `"Fn(foo)"` | | **[Function pointer]** | `rhai::FnPtr` | `Fn` | `"Fn(foo)"` |
| **[`Dynamic`] value** (i.e. can be anything) | `rhai::Dynamic` | _the actual type_ | _actual value_ | | **[`Dynamic`] value** (i.e. can be anything) | `rhai::Dynamic` | _the actual type_ | _actual value_ |
| **System integer** (current configuration) | `rhai::INT` (`i32` or `i64`) | `"i32"` or `"i64"` | `"42"`, `"123"` etc. | | **System integer** (current configuration) | `rhai::INT` (`i32` or `i64`) | `"i32"` or `"i64"` | `"42"`, `"123"` etc. |

View File

@ -4,19 +4,32 @@
{{#include ../links.md}} {{#include ../links.md}}
Avoid `String`
--------------
As must 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` `&str` Maps to `ImmutableString`
------------------------------- -------------------------------
Rust functions accepting parameters of `String` should use `&str` instead because it maps directly to Rust functions accepting parameters of `String` should use `&str` instead because it maps directly to
[`ImmutableString`][string] which is the type that Rhai uses to represent [strings] internally. [`ImmutableString`][string] which is the type that Rhai uses to represent [strings] internally.
The parameter type `String` is discouraged because it involves converting an [`ImmutableString`] into a `String`. The parameter type `String` involves always converting an [`ImmutableString`][string] into a `String`
which mandates cloning it.
Using `ImmutableString` or `&str` is much more efficient. Using `ImmutableString` or `&str` is much more efficient.
A common mistake made by novice Rhai users is to register functions with `String` parameters. A common mistake made by novice Rhai users is to register functions with `String` parameters.
```rust ```rust
fn get_len1(s: String) -> i64 { s.len() as i64 } // <- Rhai finds this function, but very inefficient fn get_len1(s: String) -> i64 { s.len() as i64 } // <- Very inefficient!!!
fn get_len2(s: &str) -> i64 { s.len() as i64 } // <- Rhai finds this function fine fn get_len2(s: &str) -> i64 { s.len() as i64 } // <- This is better
fn get_len3(s: ImmutableString) -> i64 { s.len() as i64 } // <- the above is equivalent to this fn get_len3(s: ImmutableString) -> i64 { s.len() as i64 } // <- the above is equivalent to this
engine engine
@ -24,9 +37,9 @@ engine
.register_fn("len2", get_len2) .register_fn("len2", get_len2)
.register_fn("len3", get_len3); .register_fn("len3", get_len3);
let len = engine.eval::<i64>("x.len1()")?; // error: function 'len1 (&str | ImmutableString)' not found let len = engine.eval::<i64>("x.len1()")?; // 'x' is cloned, very inefficient!
let len = engine.eval::<i64>("x.len2()")?; // works fine let len = engine.eval::<i64>("x.len2()")?; // 'x' is shared
let len = engine.eval::<i64>("x.len3()")?; // works fine let len = engine.eval::<i64>("x.len3()")?; // 'x' is shared
``` ```
@ -37,9 +50,11 @@ Rhai functions can take a first `&mut` parameter. Usually this is a good idea b
cloning of the argument (except for primary types where cloning is cheap), so its use is encouraged cloning of the argument (except for primary types where cloning is cheap), so its use is encouraged
even though there is no intention to ever mutate that argument. even though there is no intention to ever mutate that argument.
`ImmutableString` is an exception to this rule. While `ImmutableString` is cheap to clone (only [`ImmutableString`][string] is an exception to this rule.
incrementing a reference count), taking a mutable reference to it involves making a private clone
of the underlying string because Rhai has no way to find out whether that parameter will be mutated. While `ImmutableString` is cheap to clone (only incrementing a reference count), taking a mutable
reference to it involves making a private clone of the underlying string because Rhai has no way
to find out whether that parameter will be mutated.
If the `ImmutableString` is not shared by any other variables, then Rhai just returns a mutable If the `ImmutableString` is not shared by any other variables, then Rhai just returns a mutable
reference to it since nobody else is watching! Otherwise a private copy is made first, reference to it since nobody else is watching! Otherwise a private copy is made first,

View File

@ -1,7 +1,7 @@
//! Module containing implementation for custom syntax. //! Module containing implementation for custom syntax.
use crate::any::Dynamic; use crate::any::Dynamic;
use crate::engine::{Engine, Imports, State, MARKER_BLOCK, MARKER_EXPR, MARKER_IDENT}; use crate::engine::{Engine, Imports, State, MARKER_BLOCK, MARKER_EXPR, MARKER_IDENT};
use crate::error::{LexError, ParseError, ParseErrorType}; use crate::error::{LexError, ParseError};
use crate::fn_native::{SendSync, Shared}; use crate::fn_native::{SendSync, Shared};
use crate::module::Module; use crate::module::Module;
use crate::parser::Expr; use crate::parser::Expr;