11 个版本 (4 个稳定版)
3.1.0 | 2024年8月7日 |
---|---|
3.0.0 | 2024年1月15日 |
2.0.0 | 2023年8月28日 |
1.0.0 | 2023年5月29日 |
0.5.1 | 2021年12月24日 |
#122 在 Rust 模式
每月下载量 3,747
在 9 个 crate 中使用(通过 tarantool)
275KB
5K SLoC
tlua
此库是 Tarantool LuaJIT 的高层绑定。它是 Tarantool LuaJIT 的分支,经过改进和修改,以与 Tarantool LuaJIT ABI 一起使用。
如何使用它?
use tlua::Lua;
Lua
结构是此库的主要元素。它表示一个可以执行 Lua 代码的上下文。
let lua = Lua::new();
读取和写入变量
lua.set("x", 2);
lua.exec("x = x + 1").unwrap();
let x: i32 = lua.get("x").unwrap(); // x is equal to 3
可以使用 set
和 get
来读取和写入 Lua 上下文的全局变量。函数 get
返回一个 Option<T>
并复制值。
可以读取和写入的基本类型包括:i8
,i16
,i32
,u8
,u16
,u32
,f32
,f64
,bool
,String
。可以写入但不能读取 &str
。
如果您愿意,您也可以通过实现 Push
和 LuaRead
特性来添加其他类型。
执行 Lua
lua.exec("a = 2");
let x: u32 = lua.eval("return 6 * a;").unwrap(); // equals 12
exec
函数接受一个 &str
并返回 Result<(), LuaError>
。函数 eval
接受一个 &str
并返回一个 Result<T, LuaError>
,其中 T: LuaRead
。
您还可以调用 exec_from
/eval_from
,它们接受一个 std::io::Read
作为参数。例如,您可以轻松地执行文件的内容,如下所示
lua.exec_from(File::open(&Path::new("script.lua")).unwrap())
编写函数
为了编写一个函数,您必须将其包裹在 tlua::functionX
中,其中 X
是参数的数量。这是目前 Rust 推断系统的一个限制。
fn add(a: i32, b: i32) -> i32 {
a + b
}
lua.set("add", tlua::function2(add));
lua.exec("local c = add(2, 4)"); // calls the `add` function above
let c: i32 = lua.get("c").unwrap(); // returns 6
在 Lua 中,函数与普通变量完全相同。
您也可以编写普通函数以及闭包
lua.set("mul", tlua::function2(|a: i32, b: i32| a * b));
请注意,Lua 上下文的生存期必须等于或短于闭包的生存期。这是在编译时强制执行的。
let mut a = 5i;
{
let lua = Lua::new();
lua.set("inc", || a += 1); // borrows 'a'
for i in (0 .. 15) {
lua.exec("inc()").unwrap();
}
} // unborrows `a`
assert_eq!(a, 20)
错误处理
如果您的 Rust 函数返回一个包含错误的 Result
对象,则将触发 Lua 错误。
操作 Lua 表
可以通过读取 LuaTable
对象来操作 Lua 表。这可以通过轻松地读取 LuaTable
对象来实现。
let table: tlua::LuaTable<_> = lua.get("a").unwrap();
然后您可以使用 .iter()
函数遍历表。请注意,迭代器返回的值是 Option<(Key, Value)>
,当键或值不能转换为请求的类型时,Option
为空。当处理这种情况时,标准 Iterator
特性提供的 filter_map
函数非常有用。
for (key, value) in table.iter().filter_map(|e| e) {
...
}
您还可以检索和修改单个索引
let x = table.get("a").unwrap();
table.set("b", "hello");
调用 Lua 函数
您可以通过读取 functions_read::LuaFunction
来调用 Lua 函数。
lua.exec("
function get_five()
return 5
end");
let get_five: tlua::LuaFunction<_> = lua.get("get_five").unwrap();
let value: i32 = get_five.call().unwrap();
assert_eq!(value, 5);
此对象持有 Lua
的可变引用,因此当 get_five
变量存在时,您不能读取或修改 Lua 上下文中的任何内容。目前无法存储函数,但将来可能可以。
读取和写入 Rust 容器
(注意:目前尚不能读取所有容器,请参见下文)
可以一次读取和写入整个 Rust 容器
lua.set("a", [ 12, 13, 14, 15 ]);
let hashmap: HashMap<i32, f64> = [1., 2., 3.].into_iter().enumerate().map(|(k, v)| (k as i32, *v as f64)).collect();
lua.set("v", hashmap);
如果容器有单个元素,则索引将是数值。例如,在上面的代码中,12
将位于索引 1
,13
将位于索引 2
,等等。
如果容器有两个元素的元组,则第一个元素将被视为键,第二个元素将被视为值。
这可以用于创建API。
fn foo() { }
fn bar() { }
lua.set("mylib", [
("foo", tlua::function0(foo)),
("bar", tlua::function0(bar))
]);
lua.exec("mylib.foo()");
可以读取一个 Vec<AnyLuaValue>
。
let lua = Lua::new();
lua.exec(r#"v = { 1, 2, 3 }"#).unwrap();
let read: Vec<_> = lua.get("v").unwrap();
assert_eq!(
read,
[1., 2., 3.].iter()
.map(|x| AnyLuaValue::LuaNumber(*x)).collect::<Vec<_>>());
如果表表示稀疏数组,具有非数字键,或索引不是从1开始,则 .get()
将返回 None
,因为Rust的 Vec
不支持这些功能。
可以读取一个 HashMap<AnyHashableLuaValue, AnyLuaValue>
。
let lua = Lua::new();
lua.exec(r#"v = { [-1] = -1, ["foo"] = 2, [2.] = 42 }"#).unwrap();
let read: HashMap<_, _> = lua.get("v").unwrap();
assert_eq!(read[&AnyHashableLuaValue::LuaNumber(-1)], AnyLuaValue::LuaNumber(-1.));
assert_eq!(read[&AnyHashableLuaValue::LuaString("foo".to_owned())], AnyLuaValue::LuaNumber(2.));
assert_eq!(read[&AnyHashableLuaValue::LuaNumber(2)], AnyLuaValue::LuaNumber(42.));
assert_eq!(read.len(), 3);
用户数据
(注意:这里的API目前非常不稳定)
当你向Lua公开函数时,你可能希望读取或写入更复杂的数据对象。这被称为 用户数据。
要这样做,你应该为你的类型实现 Push
、CopyRead
和 ConsumeRead
。这通常通过调用 userdata::push_userdata
来完成。
struct Foo;
impl<L> tlua::Push<L> for Foo where L: tlua::AsLua {
fn push_to_lua(&self, lua: L) -> tlua::PushGuard<L> {
lua::userdata::push_userdata(self, lua,
|metatable| {
// you can define all the member functions of Foo here
// see the official Lua documentation for metatables
metatable.set("__call", tlua::function0(|| println!("hello from foo")))
})
}
}
fn main() {
let lua = lua::Lua::new();
lua.set("foo", Foo);
lua.exec("foo()"); // prints "hello from foo"
}
依赖项
~1.3–2.2MB
~46K SLoC