在C代码中,我有一个数组和一个从零开始的索引,用于在其中查找,例如:
char * names[] = {"Apple", "Banana", "Carrot"};
char * name = names[index];
Run Code Online (Sandbox Code Playgroud)
从嵌入式Lua脚本,我可以index通过一个getIndex()函数访问,并希望复制数组查找.鉴于Lua的基于单一的阵列,是否有一个同意"最佳"的方法来做到这一点?
例如,我可以使用与我的C数组相同的内容创建一个Lua数组,但这需要在索引时添加1:
names = {"Apple", "Banana", "Carrot"}
name = names[getIndex() + 1]
Run Code Online (Sandbox Code Playgroud)
或者,我可以避免使用更复杂的表添加1,但这会破坏以下内容#names:
names = {[0] = "Apple", "Banana", "Carrot"}
name = names[getIndex()]
Run Code Online (Sandbox Code Playgroud)
建议采用什么方法?
编辑:感谢您的答案到目前为止.不幸的是,在getIndex函数中向索引添加1的解决方案并不总是适用.这是因为在某些情况下索引是"众所周知的" - 也就是说,可以记录索引0表示"Apple"等等.在这种情况下,是否应优先选择上述解决方案中的一种或另一种,还是有更好的替代方案?
编辑2:再次感谢您的回答和评论,他们确实帮助我思考了这个问题.我已经意识到问题可能出现在两种不同的场景中,理想的解决方案可能各有所不同.
在第一种情况下,考虑例如可能随时间不同的阵列和仅与当前阵列相关的索引.指数在代码之外没有任何意义.Doug Currie和RBerteig是完全正确的:数组应该是基于1的,getIndex应该包含一个+1.如上所述,这允许C和Lua两侧的代码是惯用的.
第二种情况涉及具有含义的索引,并且可能是一个总是相同的数组.一个极端的例子就是names包含的地方"Zero", "One", "Two".在这种情况下,每个索引的预期值是众所周知的,我觉得将Lua端的索引设置为一个是不直观的.我认为应该首选其他方法之一.
Dou*_*rie 16
使用基于1的Lua表,并埋入函数+ 1内部getIndex.
我更喜欢
names = {[0] = "Apple", "Banana", "Carrot"}
name = names[getIndex()]
Run Code Online (Sandbox Code Playgroud)
有些表操作的特点- ,#,,insert -被打破.
其他 - ,- 要求显式启动索引正确运行:removesortconcat(t, sep, 0)unpack(t, 0)
print(table.concat(names, ',', 0)) --> Apple,Banana,Carrot
print(unpack(names, 0)) --> Apple Banana Carrot
Run Code Online (Sandbox Code Playgroud)
我讨厌不断记住这一点,+1以满足Lua默认的基于1的索引风格.
您的代码应该反映您的域特定索引更具可读性.
如果基于0的索引适合您的任务,则应在Lua中使用基于0的索引.
我喜欢在Pascal中实现数组索引:你可以自由选择你想要的任何范围,例如,array[-10..-5]of byte对于6个元素的数组来说绝对可以.
首先,这种情况并不是混合Lua和C的应用程序所独有的; 即使仅使用Lua应用程序,您也可以面对同样的问题.举一个例子,我正在使用一个编辑器组件来索引从0开始的行(是的,它是基于C的,但我只使用它的Lua接口),但是我在编辑器中编辑的脚本中的行是1-根据.因此,如果用户在第3行设置断点(从编辑器中的0开始),我需要向调试器发送一个命令,将其设置在脚本的第4行(并在命中断点时转换回来).
现在的建议.
(1)我个人不喜欢使用[0]hack进行数组操作,因为它打破了很多东西.你和叶戈尔已经列出了很多; 最重要的是我它打破#和ipairs.
(2)当使用基于1的数组时,我尽量避免索引它们并尽可能多地使用迭代器:for i, v in ipairs(...) do而不是for i = 1, #array do).
(3)我也尝试隔离处理这些转换的代码; 例如,如果要在编辑器中的行之间进行转换以管理脚本中的标记和行,那么可以使用marker2script和script2marker执行转换的函数(即使它是简单的+1和-1操作).即使没有+ 1/-1调整,你也会有这样的东西,它只是隐含的.
(4)如果你无法隐藏转换(并且我同意,+1可能看起来很难看),那么使其更加引人注目:使用执行转换的c2l和l2c调用.在我看来,它并不像+ 1/-1那样丑陋,但具有传达意图的优势,并且还为您提供了一种搜索转换所发生位置的简便方法.当您查找off-one错误或API更改导致更新此逻辑时,它非常有用.
总的来说,我不会太担心这些方面.我正在开发一个相当复杂的Lua应用程序,它包含几个基于0的C组件,并且不记得由不同索引引起的任何问题......
这是Lua metemethods和metatables派上用场的地方.使用表代理和几个元方法,您可以以适合您需要的方式修改对表的访问.
local names = {"Apple", "Banana", "Carrot"} -- Original Table
local _names = names -- Keep private access to the table
local names = {} -- Proxy table, used to capture all accesses to the original table
local mt = {
__index = function (t,k)
return _names[k+1] -- Access the original table
end,
__newindex = function (t,k,v)
_names[k+1] = v -- Update original table
end
}
setmetatable(names, mt)
Run Code Online (Sandbox Code Playgroud)
所以这里发生的是原始表有自己的代理,然后代理捕获表的每次访问尝试.访问表时,它会增加访问的值,模拟基于0的数组.以下是打印结果:
print(names[0]) --> Apple
print(names[1]) --> Banana
print(names[2]) --> Carrot
print(names[3]) --> nil
names[3] = "Orange" --Add a new field to the table
print(names[3]) --> Orange
Run Code Online (Sandbox Code Playgroud)
所有表操作都像通常一样.使用这种方法,您不必担心会破坏对表的任何非常访问.
编辑:我想指出新的"名称"表只是访问原始名称表的代理.因此,如果您查询#names结果将为nil,因为该表本身没有值.您需要查询#_names以访问原始表的大小.
编辑2:正如Charles Stewart在下面的评论中指出的那样,你可以在mt表中添加一个__len元方法,以确保#names调用能够为你提供正确的结果.
| 归档时间: |
|
| 查看次数: |
2153 次 |
| 最近记录: |