Lua中一种更好的将多个返回值分配给表键的方法

假设我有一个返回多个值的函数。我刚好在使用LÖVE的(Image):getDimensions。这返回了两个值,我知道它们是 width,height。我想将它们分配到一个新表中,作为一个数组。我想要的是已命名(字符串)键。例如,我想将 getDimensions() 函数的返回值分配到一个新表中,其中 widthheight 都是键。

我知道以下代码可以工作...

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不熟悉(现在约两天),所以可能有另一种标准函数或最佳做法,可以将一个键的表关联到类似于数组的表中。谢谢!

点赞
用户1847592
用户1847592

你可以编写自己的函数:

local function set_fields(tab, fields, ...)
   -- fields是一个字段名称的数组
   -- (使用空字符串跳过相应位置的值)
   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
-- 我们想以不同的顺序保存返回的值
local weekdays = set_fields({}, {7,1,2,3,4,5,6}, get_weekdays())
-- 现在weekdays包含{"Mon", "Tue", "Wed", "Thu", "Fri", "Sat", "Sun"}

用法示例#3:

local function get_coords_x_y_z()
   return 111, 222, 333  -- 点的x、y、z
end
-- 我们想在地平面上获取点的投影
local projection = {y = 0}
-- projection.y将被保留,projection.x和projection.z将被修改
set_fields(projection, {"x", "", "z"}, get_coords_x_y_z())
-- 现在projection包含{x = 111, y = 0, z = 333}

用法示例#4:

如果 require("some_module") 返回一个具有许多函数的模块,但您只需要其中的几个函数:

local bnot, band, bor = get_fields(require("bit"), {"bnot", "band", "bor"})
2017-01-01 21:51:43
用户4342563
用户4342563

使用类构造,我得出以下结果...

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

然后我可以以多种方式初始化一个大小对象

  • 使用多个返回值:

    • 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({})
  • 使用混合数组和哈希表:

    • image.size = Size.new({height=20, width=30})
    • image.size = Size.new({height=20, 30})

这种方法与 Egor 的方法(实用函数)相比有优劣之分,如果没有一个简单的语法技巧或我不知道的现有函数的话,我考虑采用 Egor 的方法。

优点:

  • (个人)在 Lua 中学习 OO 构造的经验
  • 我可以限制表中实际键的数量,同时允许通过扩展 __index__newindex 中接受的值来添加 'synonyms'(同义词)这些键
  • 明确定义表中的字段,无需担心使用通用工具函数时需要同步键表和值表。

缺点:

  • 需要为每个想要使用此行为的数据结构重复此模式
  • 代价高,对于消费者来说,这相当于非常小的差异所产生的大量开销

我相信我可以随着时间的推移使这种方法更加健壮,但是我会感谢任何反馈。

2017-01-01 22:54:06