将多个 return 值分配给 Lua 中的 table 键的更好方法
A better way to assign multiple return values to table keys in Lua
假设我有一个 return 多个值的函数。我碰巧和 LÖVE 的 (Image):getDimensions
一起工作。这 return 的两个值,我知道是 width,height
。我想将它们分配给一个新的 table,作为一个数组。我想要命名(字符串)键。因此,例如,我想将 getDimensions()
函数的 return 值分配给一个新的 table,键分别为 width
和 height
。
我知道以下作品...
image = {}
image.data = love.graphics.newImage('myimage.png')
image.size = {}
image.size.width, image.size.height = image.data:getDimensions()
我想知道是否有任何类型的语法糖我可以使用,或者任何标准库函数的使用都将允许更多的语法......
image.size = { width, height = image.data:getDimensions() }
我知道上面这行行不通,我尝试了很多变体,包括使用 unpack()
的各种尝试。我是 Lua 的新手(现在大约 2 天),所以也许还有另一个我不知道的标准函数或最佳实践会将 table 键关联到类似数组table。谢谢!
您可以编写自己的函数:
local function set_fields(tab, fields, ...)
-- fields is an array of field names
-- (use empty string to skip value at corresponging position)
local values = {...}
for k, field in ipairs(fields) do
if field ~= "" then
tab[field] = values[k]
end
end
return tab
end
local function get_fields(tab, fields)
local values = {}
for k, field in ipairs(fields) do
values[k] = tab[field]
end
return (table.unpack or unpack)(values, 1, #fields)
end
用法示例#1:
image.size = set_fields({}, {"width", "height"}, image.data:getDimensions())
用法示例#2:
即时交换值!
local function get_weekdays()
return "Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"
end
-- we want to save returned values in different order
local weekdays = set_fields({}, {7,1,2,3,4,5,6}, get_weekdays())
-- now weekdays contains {"Mon", "Tue", "Wed", "Thu", "Fri", "Sat", "Sun"}
用法示例#3:
local function get_coords_x_y_z()
return 111, 222, 333 -- x, y, z of the point
end
-- we want to get the projection of the point on the ground plane
local projection = {y = 0}
-- projection.y will be preserved, projection.x and projection.z will be modified
set_fields(projection, {"x", "", "z"}, get_coords_x_y_z())
-- now projection contains {x = 111, y = 0, z = 333}
用法示例#4:
如果require("some_module")
returns一个模块里面有很多功能,但你只需要其中的几个:
local bnot, band, bor = get_fields(require("bit"), {"bnot", "band", "bor"})
使用 class 构造,我想出了以下...
Size = {}
Size.mt = {}
Size.prototype = { width = 0, height = 0 }
function Size.new (dimensions)
local size = setmetatable({}, Size.mt)
if dimensions ~= nil and type(dimensions) == 'table' then
for k,v in pairs(dimensions) do
size[k] = v
end
end
return size
end
Size.mt.__index = function (t, k)
if k == 'width' or k == 'height' then
rawset(t, k, Size.prototype[k])
return t[k]
else
return nil
end
end
Size.mt.__newindex = function (t, k, v)
if k == 1 or k == 'width' then
rawset(t, 'width', v)
elseif k == 2 or k == 'height' then
rawset(t, 'height', v)
end
end
然后我可以通过多种方式初始化 Size 对象
- 使用多个 return 值:
image.size = Size.new{image.data:getDimensions()}
image.size = Size.new(table.pack(image.data:getDimensions())
- 使用默认值:
image.size = Size.new()
image.size = Size.new{}
image.size = Size.new({})
- 使用混合数组和散列 tables:
image.size = Size.new({height=20, width=30})
image.size = Size.new({height=20, 30})
与 Egor 的(效用函数)相比,这种方法有利有弊,如果没有简单的语法技巧或我不知道的现有函数,我正在考虑这样做。
优点:
- (个人)在 Lua
中使用 OO 构造的学习经验
- 我可以限制 table 上的实际键的数量,同时允许通过扩展
if/else
逻辑中接受的值来为这些键添加 'synonyms' __index
和 __newindex
- table 中字段的显式定义,无需担心将 table 键与 table 值同步(与通用实用函数一样)
缺点
- 需要为我想要此行为的每个数据结构重复此模式
- 成本高,对消费者来说差异很小,但需要大量开销
我确信我可以及时使这种方法更健壮,但我将不胜感激任何反馈。
假设我有一个 return 多个值的函数。我碰巧和 LÖVE 的 (Image):getDimensions
一起工作。这 return 的两个值,我知道是 width,height
。我想将它们分配给一个新的 table,作为一个数组。我想要命名(字符串)键。因此,例如,我想将 getDimensions()
函数的 return 值分配给一个新的 table,键分别为 width
和 height
。
我知道以下作品...
image = {}
image.data = love.graphics.newImage('myimage.png')
image.size = {}
image.size.width, image.size.height = image.data:getDimensions()
我想知道是否有任何类型的语法糖我可以使用,或者任何标准库函数的使用都将允许更多的语法......
image.size = { width, height = image.data:getDimensions() }
我知道上面这行行不通,我尝试了很多变体,包括使用 unpack()
的各种尝试。我是 Lua 的新手(现在大约 2 天),所以也许还有另一个我不知道的标准函数或最佳实践会将 table 键关联到类似数组table。谢谢!
您可以编写自己的函数:
local function set_fields(tab, fields, ...)
-- fields is an array of field names
-- (use empty string to skip value at corresponging position)
local values = {...}
for k, field in ipairs(fields) do
if field ~= "" then
tab[field] = values[k]
end
end
return tab
end
local function get_fields(tab, fields)
local values = {}
for k, field in ipairs(fields) do
values[k] = tab[field]
end
return (table.unpack or unpack)(values, 1, #fields)
end
用法示例#1:
image.size = set_fields({}, {"width", "height"}, image.data:getDimensions())
用法示例#2:
即时交换值!
local function get_weekdays()
return "Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"
end
-- we want to save returned values in different order
local weekdays = set_fields({}, {7,1,2,3,4,5,6}, get_weekdays())
-- now weekdays contains {"Mon", "Tue", "Wed", "Thu", "Fri", "Sat", "Sun"}
用法示例#3:
local function get_coords_x_y_z()
return 111, 222, 333 -- x, y, z of the point
end
-- we want to get the projection of the point on the ground plane
local projection = {y = 0}
-- projection.y will be preserved, projection.x and projection.z will be modified
set_fields(projection, {"x", "", "z"}, get_coords_x_y_z())
-- now projection contains {x = 111, y = 0, z = 333}
用法示例#4:
如果require("some_module")
returns一个模块里面有很多功能,但你只需要其中的几个:
local bnot, band, bor = get_fields(require("bit"), {"bnot", "band", "bor"})
使用 class 构造,我想出了以下...
Size = {}
Size.mt = {}
Size.prototype = { width = 0, height = 0 }
function Size.new (dimensions)
local size = setmetatable({}, Size.mt)
if dimensions ~= nil and type(dimensions) == 'table' then
for k,v in pairs(dimensions) do
size[k] = v
end
end
return size
end
Size.mt.__index = function (t, k)
if k == 'width' or k == 'height' then
rawset(t, k, Size.prototype[k])
return t[k]
else
return nil
end
end
Size.mt.__newindex = function (t, k, v)
if k == 1 or k == 'width' then
rawset(t, 'width', v)
elseif k == 2 or k == 'height' then
rawset(t, 'height', v)
end
end
然后我可以通过多种方式初始化 Size 对象
- 使用多个 return 值:
image.size = Size.new{image.data:getDimensions()}
image.size = Size.new(table.pack(image.data:getDimensions())
- 使用默认值:
image.size = Size.new()
image.size = Size.new{}
image.size = Size.new({})
- 使用混合数组和散列 tables:
image.size = Size.new({height=20, width=30})
image.size = Size.new({height=20, 30})
与 Egor 的(效用函数)相比,这种方法有利有弊,如果没有简单的语法技巧或我不知道的现有函数,我正在考虑这样做。
优点:
- (个人)在 Lua 中使用 OO 构造的学习经验
- 我可以限制 table 上的实际键的数量,同时允许通过扩展
if/else
逻辑中接受的值来为这些键添加 'synonyms'__index
和__newindex
- table 中字段的显式定义,无需担心将 table 键与 table 值同步(与通用实用函数一样)
缺点
- 需要为我想要此行为的每个数据结构重复此模式
- 成本高,对消费者来说差异很小,但需要大量开销
我确信我可以及时使这种方法更健壮,但我将不胜感激任何反馈。