Lua Printf |
|
printf 字符串格式化函数。
使用 io.write()、print() 和 string.format() 在 Lua 中编写格式化文本很容易。io.write 与 print 类似,只是 io.write 不会在每个输出后添加换行符。C 函数 printf() 可以模拟为
> io.write(string.format("Hello from %s on %s\n",_VERSION,os.date())) Hello from Lua 5.1 on Mon Jan 1 22:11:56 2007
或者,可以将其封装在一个函数中,如下所示:
printf = function(s,...) return io.write(s:format(...)) end -- function
然后可以像这样使用:
printf("Hello from %s on %s\n",_VERSION,date())
在上面的示例中,printf() 的格式字符串和可变参数列表被传递给 string.format()。write() 打印生成的格式化字符串。[*1]
有趣的是,Lua 5.1 中字符串方法的语法强制对第一个参数进行单独处理。这是有道理的,因为它与其他参数的作用完全不同。
请注意,Lua 的 string.format 函数不支持完整的 C 格式规范 [1],因此此函数不能直接替换。如果您需要 C 格式规范的全部功能,您可能需要在 C 代码中执行 printf 调用,然后从 Lua 中调用它。或者,您可以使用 C 字符串函数在 Lua 中完全模拟您需要的行为(更多工作量)。
上面的示例可以用 C 代码编写如下。这还通过捕获两个标准库函数作为上值来进行优化,而不是每次都查找它们(尽管每次都查找它们具有更动态的优势)。不过,您可能只想使用 Lua 版本。
static int l_printf (lua_State *L) {
lua_pushvalue(L, lua_upvalueindex(2));
lua_insert(L, 1);
lua_call(L, lua_gettop(L) - 1, 1);
lua_pushvalue(L, lua_upvalueindex(1));
lua_pushvalue(L, -2);
lua_call(L, 1, 0);
return 0;
}
int luaopen_printf (lua_State *L) {
lua_getglobal(L, "io");
lua_getglobal(L, "string");
lua_pushliteral(L, "write");
lua_gettable(L, -3);
lua_pushliteral(L, "format");
lua_gettable(L, -3);
lua_pushcclosure(L, l_printf, 2);
/* With 5.1, I'd probably just return 1 at this point */
lua_setglobal(L, "printf");
return 0;
}
一个 C 函数 l_printf 在 Lua 中注册为 printf。当从 Lua 调用 l_printf 时,format() 会使用给定的参数调用,然后 write() 会使用 format 的结果调用,最后返回结果的数量。
脚注
[*1] Lua 4 版本为
function printf(...) write(call(format,arg)) end
static int l_printf (lua_State *l)
{
lua_getglobal(L,"format");
lua_insert(L,1);
lua_call(L,lua_gettop(L)-1,LUA_MULTRET);
lua_getglobal(L,"write");
lua_insert(L,1);
lua_call(L,lua_gettop(L)-1,LUA_MULTRET);
return lua_gettop(L);
}
lua_register(L,"printf",l_printf);
pcall() 包装器来捕获错误并指向有问题的 printf()。否则很难确切地知道错误来自哪里。
function printf(...) local function wrapper(...) io.write(string.format(...)) end local status, result = pcall(wrapper, ...) if not status then error(result, 2) end end