当前位置: 首页 > 工具软件 > z.lua > 使用案例 >

Lua 5.3中的新功能

董畅
2023-12-01

並未涵蓋所有Lua 5.3的所有新功能。
Lua 5.3 主要特性如下:
“number”類型包含兩種內部類型,即“integer”與“float”,因为 Lua 的意识形态没有改变,它仍然试图保护用户免受数字类型的干扰。内部类型称为子类型,如何获取包含数字的变量的子类型?
對於本机位运算符的支持。警告,在默认安装中它们是 64 位的,很少支持 UTF-8
Lua 5.3 安装提供了“integer”和“float”大小的特定配置:
64-bit integer and 64-bit double (叫做 “Standart Lua”, 默認)
– #define LUA_INT_LONGLONG, #define LUA_REAL_DOUBLE
32-bit integer and 32-bit float (叫做 “Small Lua”)
– #define LUA_INT_INT, #define LUA_REAL_FLOAT
很少混合使用。
可以在 luaconf.h 中进行配置,只需找到“#define LUA_INT_LONGLONG”、“#define LUA_REAL_DOUBLE”行并将它们更改为你需要的。
有点奇怪的是,有定义“integer”类型的 LUA_INTEGER 宏定义,并且没有应该用来定义“float”类型的 LUA_FLOAT 宏定义,作者决定使用旧的 LUA_NUMBER 宏定义,希望这会不会造成混乱和bug。
通過擼代碼來學習這些變化,大部分代码基于 Lua 5.3 测试套件。

local debug = require("debug")
print(debug.Csize('I') .. "-bit integers") -- 64-bit integers
print(debug.Csize('F') .. "-bit floats") -- 64-bit floats
local numInteger = 2
print(type(numInteger)) -- "number"
print(math.type(numInteger)) -- "integer"
local numFloat = 2.0
print(type(numFloat)) -- "number"
print(math.type(numFloat)) -- "float"
-- for non-numeric types it just returns "nil"
print(math.type("")) -- "nil"
print(math.type("10")) -- "nil"
print(math.type({})) -- "nil"
print(math.type(nil)) -- "nil"

有一个有趣的整数与字符串运算(更类似于 JavaScript)和新的整数除法运算符:

assert(10/20 == 0.5)
assert(10-20 == -10)
assert(10*-20 == -200)
assert(10^3 == 1000)
assert(10/"20" == 0.5)
assert("10"-"20" == -10)
assert("10"*"-20" == -200)
assert("10"^"3" == 1000)
assert(2/0 == 10.0/0)
assert(10 // 3 == 3) -- this operator seems changed from "\" to "//"
assert(math.type(10 // 3) == "integer")
assert(10 + 3 == 13)
assert(math.type(10 + 3) == "integer")
assert(10.0 + 3 == 13.0)
assert(math.type(10.0 + 3) == "float")
assert(10 + 3.0 == 13.0)
assert(math.type(10 + 3.0) == "float")
assert(4 % -3 == -2)
assert(8 % (4 + (-3)*2) == 0)
 
assert(not pcall(function() return 10 // 0 end))
assert(not pcall(function() return 10 // 2.0^90 end)) -- integer overflow
assert(not pcall(function() return 10 % 0 end)0

将整型转换为浮点型

assert(math.type(numInteger) == "integer")
numFloat = numInteger + 0.0 -- convert integer to float
assert(math.type(numFloat) == "float")

整数溢出的情況:

print(1000*1000*1000*1000*1000*1000) -- 1000000000000000000
print(1000*1000*1000*1000*1000*1000*10) -- -8446744073709551616
print(1000*1000*1000*1000*1000*1000*100) -- 7766279631452241920
print(1000*1000*1000*1000*1000*1000*100.0) -- 1e+20 = 100000000000000000000.0
print(0x7FFFFFFFFFFFFFFF) -- maximal 64-bit signed integer 9223372036854775807
print(0x7FFFFFFFFFFFFFFF + 1) -- wrap to -9223372036854775808
print(0x8000000000000000) -- minimal 64-bit signed integer -9223372036854775808
print(0x8000000000000000 - 1) -- wrap to 9223372036854775807

按位运算:

local a = -1
a = 0xFFFFFFFFFFFFFFFF -- also -1
a = 0 - 1 -- also -1
assert(a & -1 == -1) -- masking with 0xFFFFFFFFFFFFFFFF preserves original integer -1
assert(35 & -1 == 35) -- masking with 0xFFFFFFFFFFFFFFFF preserves original integer 35
assert(~0 == -1) -- inverting bits using Logical Unary NOT
 
a = 0xF0F0F0F0F0F0F0F0
assert(a | -1 == -1)
assert(a ~ a == 0) -- reminded me "XOR eax, eax" 
assert(a ~ 0 == a)
assert(a ~ ~a == -1)
assert(a >> 4 == ~a)

UTF-8的使用:

local function utf8_len(str)
    return #str - select(2, string.gsub(str, "[\x80-\xBF]", function() end))
end
 
local str = "Συρακούσα"
print(#str, utf8_len(str), utf8.len(str)) -- will print 19     9      9
str = '\u{03a3}\u{03c5}\u{03c1}\u{03b1}\u{03ba}\u{03bf}\u{1f7b}\u{03c3}\u{03b1}' -- same string encoded
print(str)

从版本 Lua 5.2/5.1 移植代码:
我必须对我的代码做的最重要的更改与 tostring() 函数有关,可能在你的情况下,它也是 __tostring。問題是如果我们尝试打印具有子类型“float”的“number”类型的变量,即使它里面有整数值,它也会在最后打印“.0”。

local a = 8.0
local b = 4.0
local num = a / b
print(tostring(num)) -- will print "2.0"
print(num) -- tostring() called internally inside print()
-- but beware table.concat() uses __concat which differes from __tostring logic and makes me sad!
local t = { "I want to print integer without dot and digits after dot ", num }
print(table.concat(t)) -- will print "I want to print integer without dot and digits after dot 2"
t[1] = "I want to print float "
t[2] = 2.3
print(table.concat(t)) -- will print "I want to print float 2.3"
 
-- there is also cave it that you can't create float keys containing integers, for example
t[2.0] = 456 - will be still t[2] so you can assign t[1.0], t[2.0], t[3.0] and iterate using ipairs() or for i, 3, 1 do <...> end,
--- but everything else is same as in previous versions:
t[2.4] = 77 - will be t[2.4], and of course
t['2'], t['2.0'], t['2.4'] = 8, 9, 10 - will be all different string keys

要解决這個问题,就需要使用 string.format() 显式指定格式:

print(tostring(num)) -- "2.0"
print(string.format("%d", num)) -- "2"
print(("%d"):format(num)) -- short version which I prefer more

顺便说一句,短期版本之所以有效,是因为:

local string = require("string") -- ensure that "string" library is specified in loadedlibs[] or preloadedlibs[] in linit.c
assert(debug.getmetatable("").__index == string)

这是 Lua 最牛逼的事情之一!

涉及整数的计算现在会导致溢出,但它们不是errors,而只是静默溢出,目前還不知道如何解决。但是严格控制所有计算都是整数可以带来一些性能优势。当然,对于繁重的计算,你不应该使用 Lua VM,使用 C/C++ 库甚至更好的 OpenCL。

为了与以前都是 32 位的位库兼容,您可以在 /usr/share/lua/5.3/bit32.lua 或 /usr/local/share/lua/5.3/bit32.lua 中创建类似的内容:

local bit32 = { }
bit32.bnot = function(a)
    return ~a & 0xFFFFFFFF
end
bit32.band = function(a, b)
    return a & b
end
bit32.bor = function(a, b)
    return (a | b) & 0xFFFFFFFF
end
bit32.bxor = function(a, b)
    return (a ~ b) & 0xFFFFFFFF
end
bit32.lshift = function(a, b)
    return (a << b) & 0xFFFFFFFF
end
bit32.rshift = function(a, b)
    return a >> b
end
return bit32

完全兼容 Lua 5.2 的 bit32 库:

-- no built-in 'bit32' library: implement it using bitwise operators
local bit32 = {}

function bit32.bnot (a)
  return ~a & 0xFFFFFFFF
end
--
-- in all vararg functions, avoid creating 'arg' table when there are
-- only 2 (or less) parameters, as 2 parameters is the common case
-- 
function bit32.band (x, y, z, ...)
  if not z then
    return ((x or -1) & (y or -1)) & 0xFFFFFFFF
  else
    local arg = {...}
    local res = x & y & z
    for i = 1, #arg do res = res & arg[i] end
    return res & 0xFFFFFFFF
  end
end
 
function bit32.bor (x, y, z, ...)
  if not z then
    return ((x or 0) | (y or 0)) & 0xFFFFFFFF
  else
    local arg = {...}
    local res = x | y | z
    for i = 1, #arg do res = res | arg[i] end
    return res & 0xFFFFFFFF
  end
end
 
function bit32.bxor (x, y, z, ...)
  if not z then
    return ((x or 0) ~ (y or 0)) & 0xFFFFFFFF
  else
    local arg = {...}
    local res = x ~ y ~ z
    for i = 1, #arg do res = res ~ arg[i] end
    return res & 0xFFFFFFFF
  end
end
 
function bit32.btest (...)
  return bit32.band(...) ~= 0
end
 
function bit32.lshift (a, b)
  return ((a & 0xFFFFFFFF) << b) & 0xFFFFFFFF
end
 
function bit32.rshift (a, b)
  return ((a & 0xFFFFFFFF) >> b) & 0xFFFFFFFF
end
 
function bit32.arshift (a, b)
  a = a & 0xFFFFFFFF
  if b <= 0 or (a & 0x80000000) == 0 then
    return (a >> b) & 0xFFFFFFFF
  else
    return ((a >> b) | ~(0xFFFFFFFF >> b)) & 0xFFFFFFFF
  end
end
 
function bit32.lrotate (a ,b)
  b = b & 31
  a = a & 0xFFFFFFFF
  if b ~= 0 then
    a = (a << b) | (a >> (32 - b))
  end
  return a & 0xFFFFFFFF
end
 
function bit32.rrotate (a, b)
  return bit32.lrotate(a, -b)
end
 
local function checkfield (f, w)
  w = w or 1
  assert(f >= 0, "field cannot be negative")
  assert(w > 0, "width must be positive")
  assert(f + w <= 32, "trying to access non-existent bits")
  return f, ~(-1 << w)
end
 
function bit32.extract (a, f, w)
  local f, mask = checkfield(f, w)
  return (a >> f) & mask
end
 
function bit32.replace (a, v, f, w)
  local f, mask = checkfield(f, w)
  v = v & mask
  a = (a & ~(mask << f)) | (v << f)
  return a & 0xFFFFFFFF
end
 
return bit32

https://devhacksandgoodies.wordpress.com/2014/05/06/whats-new-in-lua-5-3/

 类似资料: