"Hello" .. "World" --> Hello World
"result is" .. 3 --> result is 3
print(3 + 5) --> 8
print(3 .. 5) --> 35
使用限制:
连接的元素只能是数字或字符串
在连接数字时,与数字中间一定要有空格,不然会报错。在书写时,最好保证无论连接什么类型,..左右都有空格。
print(3..5) --> script.lua:2: malformed number near '3..'
print(3 .. {}) --> script.lua:2: attempt to concatenate a table value
stack traceback:
script.lua:2: in main chunk
[C]: in ?
Exited with error status 1
使用运算符..,每次拼接都需要申请新的空间,旧的 result 对应的空间会在某时刻被Lua的垃圾回收期GC,且随着result不断增长,越往后会开辟更多新的空间,并进行拷贝操作,产生更多需要被GC的空间,所以性能降低。
table.concat(table, sep, start, end)函数列出table数组部分从start位置到end位置的所有元素,元素之间以分隔符sep隔开。
fruits = {“banana”, “orange”, “apple”}
print(table.concat(fruits)) --> bananaorangerapple
print(table.concat(fruits,”,”)) --> banana,orange,apple print(table.concat(fruits, ”,”, 2, 3)) --> orange, apple
使用限制:
连接元素必须是字符串或数字。
必须先把所有待拼接元素放入一个table里面,使用起来可能不太方便
源码:
concat内部实现函数是tocancat,如下:
static const lua_Reg tab_funcs[] = { {"concat", tconcat}, ... }
下面简单解释一下toconcat函数
static int tconcat (lua_State *L) { // table.concat的参数都存放在栈上,可以简单理解为: // 栈1号位存的是table // 栈2号位存的是sep // 栈3、4号位存的是起始(start)和结束(end)的位置
// 先从2号位置取出sep,如果2号位置是nil,即没有指定sep,则sep=""
const char *sep = luaL_optlstring(L, 2, "", &lsep);
// 检查栈1号位置存的数据类型是否是一个table
luaL_checktype(L, 1, LUA_TTABLE);
// i table起始索引,如果起始索引为nil,则默认从1开始
i = luaL_optint(L, 3, 1);
// last table结束索引,如果结束索引为nil,则默认为table数组部分大小。
last = luaL_opt(L, luaL_checkint, 4, luaL_getn(L, 1));
// 申请一块buff,存合并后的数据,初始buff大小为8192
// 当buff大小用完后就直接用luaV_concat在栈上做字符串连接
luaL_buffinit(L, &b);
// 把table里面索引从i到last的值取出来,并放到buff里面,buff大小为BUFSIZ(8192)
// 每当写满一个buff,就把buff生成一个TString,并放到栈上,并把buff清空重新写
for (; i < last; i++) {
addfield(L, &b, i);
luaL_addlstring(&b, sep, lsep);
}
// 把最后一个元素放入buff
// 把buff生成一个TString,并放到栈上
if (i == last)
addfield(L, &b, i);
// 把栈上之前所有生成的TString通过luaV_concat(就是 .. 语法糖的合并函数)合并成一个TString,放到栈上,相当于返回值,供上层函数取用
luaL_pushresult(&b);
return 1;
}
性能分析:
从源码上看,table.concat没有频繁申请内存,只有当写满一个8192的BUFF时,才会生成一个TString,最后生成多个TString时,会有一次内存申请并合并。在大规模字符串合并时,应尽量选择这种方式。
table.concat 底层拼接字符串的方式也是使用运算符.. ,但是其使用算法减少了使用运算符..的次数,减少了GC,从而提高效率。
Lua string模块内置的format函数,和c语言的printf类似,可以将不同类型的数据格式化成字符串。
格式:string.format(fmt, [...])
格式化字符串可能包含一下转义码:
%c - 接受一个数字, 并将其转化为ASCII码表中对应的字符 %d, %i - 接受一个数字并将其转化为有符号的整数格式 %o - 接受一个数字并将其转化为八进制数格式 %u - 接受一个数字并将其转化为无符号整数格式 %x - 接受一个数字并将其转化为十六进制数格式, 使用小写字母 %X - 接受一个数字并将其转化为十六进制数格式, 使用大写字母 %e - 接受一个数字并将其转化为科学记数法格式, 使用小写字母e %E - 接受一个数字并将其转化为科学记数法格式, 使用大写字母E %f - 接受一个数字并将其转化为浮点数格式 %g(%G) - 接受一个数字并将其转化为%e(%E, 对应%G)及%f中较短的一种格式 %q - 接受一个字符串并将其转化为可安全被Lua编译器读入的格式 %s - 接受一个字符串并按照给定的参数格式化该字符串
为进一步细化格式,可以在%号后面添加参数,参数将以如下的顺序读入:
符号:一个+号表示其后的数字转义符将让正数显示正号,默认情况下只有负数显示符号。
占位符:一个0,在后面指定了字符串宽度时占位用,不填0时的默认占位符是空格。
对齐标识:在指定了字符串宽度时,默认为右对齐,增加-号可变为左对齐。
宽度数值
小数位数/字串裁切:在宽度数值后增加的小数部分n, 若后接f(浮点数转义符, 如%6.3f)则设定该浮点数的小数只保留n位, 若后接s(字符串转义符, 如%5.3s)则设定该字符串只显示前n位。
实例:
string1 = "mynameisbb"; number1 = 123456 number2 = 123.456 print(string.format("%.4s,%+08d,%.2f",string1,number1,number2)) --> myna,+0123456,123.46
性能分析:
字符串的连接指令比格式化要安全一些,因为格式化函数字符串的长度限制在512。而连接字符串没有这个限制。
格式化字符串的操作比较复杂,消耗会多一些。
lua string内置模块中另一个可以做字符串连接是rep,不过使用局限性大,只能重复的对某一个字符串做N次拼接。
示例:
string.rep("abc",3) --> abcabcabc
table.concat()优于字符串连接符..
字符串连接符优于格式化字符串
其中部分内容参考学习blog.csdn.net/fengshenyun…