4 个版本
0.1.0 | 2021年2月11日 |
---|---|
0.0.7 |
|
0.0.5 |
|
0.0.4 |
|
2096 在 Rust 模式
140 每月下载量
1.5MB
11K SLoC
exprtk_rs
Rust 对 ExprTk 库的绑定。
至少需要 Runst 版本 1.37。
- 文档
- 运行
cargo bench
比较执行时间(也与本地执行进行比较) - 模糊测试已被用于进一步验证 API (请参阅 FUZZING.md)
lib.rs
:
该软件包提供了对 ExprTk 库的绑定。
有关数据结构的概述,请参阅 ExprTk 主页。虽然 exprtk-sys
将库的大部分功能映射到 Rust,但高级绑定得到了显著简化。每个 Expression 都拥有一个 SymbolTable,它们不能在不同实例之间共享,并且每个表达式不可能有多个符号表。
变量属于 SymbolTable
实例。添加变量(add_variable())、字符串(add_stringvar())、向量(add_vector())的函数都返回 usize
,这是一个表示内部数据结构中值索引的 变量ID。它可以用来稍后获取符号值和修改它们。标量可以通过可变引用或通过 std::cell::Cell
类型进行修改,而无需对 SymbolTable
进行可变访问。字符串使用 set_string() 进行修改,这需要可变访问。由于通过变量ID进行访问和修改需要边界检查,因此这些操作比C++中通过指针直接修改要慢。性能影响对于运行时间快的简单表达式更为明显,但在大多数情况下似乎并不成问题。运行 cargo bench
来查看影响(与不安全版本比较)。对于每种数据类型(标量、字符串和向量),访问ID从零开始,并在添加新变量时递增。
由于无法保证 double
总是 f64
,因此库中所有地方都使用了 c_double
类型。目前不支持其他精度。
ExprTk 不处理非ASCII编码,因此变量名和公式会检查非ASCII字符或空字节,并且将出错。
示例
此代码对应于 ExprTk 文档中的 示例 1
use exprtk_rs::*;
let expression_string = "clamp(-1.0,sin(2 * pi * x) + cos(x / 2 * pi),+1.0)";
let mut symbol_table = SymbolTable::new();
symbol_table.add_constants();
let var_id = symbol_table.add_variable("x", 0.).unwrap().unwrap();
let mut expression = Expression::new(expression_string, symbol_table).unwrap();
// this value is a reference to a std::cell::Cell that can be changed
expression.symbols().value_cell(var_id).set(-5.);
while expression.symbols().value(var_id) <= 5. {
let y = expression.value();
println!("{}\t{}", expression.symbols().value(var_id), y);
*expression.symbols_mut().value_mut(var_id) += 0.001;
}
未知变量
表达式中的未知变量可以自动添加到符号表中。函数 Expression::parse_vars
将返回一个包含新添加的变量名及其变量ID的 Vec
。这仅适用于常规变量,不适用于字符串或向量。
use exprtk_rs::*;
let expr_string = "a*x^2 + b*x + c";
let (mut expr, unknown_vars) = Expression::parse_vars(expr_string, SymbolTable::new()).unwrap();
assert_eq!(
unknown_vars,
vec![("a".to_string(), 0), ("x".to_string(), 1), ("b".to_string(), 2), ("c".to_string(), 3)]
);
// modify the values
expr.symbols().value_cell(0).set(2.); // a
expr.symbols().value_cell(2).set(3.); // b
expr.symbols().value_cell(3).set(1.); // c
expr.symbols().value_cell(1).set(5.); // x
assert_eq!(expr.value(), 66.);
使用字符串的示例
use exprtk_rs::*;
let mut symbol_table = SymbolTable::new();
let s1_id = symbol_table.add_stringvar("s1", "Hello").unwrap().unwrap();
let s2_id = symbol_table.add_stringvar("s2", "world!").unwrap().unwrap();
// concatenation
let mut expr = Expression::new("s1 + ' ' + s2 == 'Hello world!'", symbol_table).unwrap();
// a boolean `true` is represented by `1`
assert_eq!(expr.value(), 1.);
// Modifying a string
expr.symbols_mut().set_string(s1_id, "");
assert_eq!(expr.value(), 0.);
函数
目前可以添加具有最多十个标量参数的函数/闭包。示例
use exprtk_rs::*;
let mut symbol_table = SymbolTable::new();
symbol_table.add_func2("add", |x, y| x + y);
symbol_table.add_variable("x", 1.).unwrap();
let mut expr = Expression::new("add(x, 1)", symbol_table).unwrap();
assert_eq!(expr.value(), 2.);