Lua2.4 参考手册(六)

(接上篇)
--------------------------------------
8 一些例子
--------------------------------------
本段给出一些显示 Lua 特性的例子。它并不打算覆盖完整的语言,只是显示一有趣的使用。

-------------------
8.1 数据结构
-------------------
表是统一的数据结构。它可以实现多种数据类型,像通常的数组,记录,集合,包,和列表。
数组不用解释。在 Lua 中,索引通常从 1 开始,但这只是个惯例。数组可以以 0 ,负数,或者其它的任何值(除了 nil)作为索引。记录也像平常一样用语法糖 a.x 实现。
最好的实现集合的方法是把它的元素保存为表的索引。语句 s={} 新建一个空集合 s。语句 s[x] = 1 把 x 的值插入到集合 s。表达式 s[x] 为真如果 x 属于 s。最后,语句 s[x] = nil 把 x 从 s 中删除。
包的实现方式和集合差不多,但是用和元素相关的值作为计数器。所以,为插入一个元素,可以用下面的代码:
if s[x] then s[x] = s[x]+1
else s[x] = 1 end
删除一个元素可以用下面的代码:
if s[x] then s[x] = s[x]-1 end
if s[x] == 0 then s[x] = nil end
Lisp 风格的列表也有一个简单的实现。二个元素 x 和 y 的 "cons" 可以由代码 l = {car=x, cdr=y} 建立。表达式 l.car 取得头,l.cdr 取得尾。另一个方法是直接用 l={x,y} 新建列表,然后用l[1] 取得头,用 l[2] 取得尾。

-------------------
8.2 函数 next 和 nextvar
-------------------
这个例子显示如何使用函数 next 去遍历一个表的字段。函数 clone 接受一个 table 并且返回它的一个克隆。
function clone (t) -- t is a table
  local new_t = {} -- create a new table
  local i, v = next(t, nil) -- i is an index of t, v = t[i]
  while i do
    new_t[i] = v
    i, v = next(t, i) -- get next index
  end
  return new_t
end
这个例子打印所有值非空的全局变量的名字
function printGlobalVariables ()
  local i, v = nextvar(nil)
  while i do
    print(i)
    i, v = nextvar(i)
  end
end
-------------------
8.3 字符串操作
-------------------
这个例子去掉字符串前后的空白:
function trim(s)
  local l = 1
  while strsub(s,l,l) == ‘ ‘ do
    l = l+1
  end
  local r = strlen(s)
  while strsub(s,r,r) == ‘ ‘ do
    r = r-1
  end
  return strsub(s,l,r)
end
这个例子去掉字符串所有的空白:
function remove_blanks (s)
  local b = strfind(s, ‘ ‘)
  while b do
    s = strsub(s, 1, b-1) .. strsub(s, b+1)
    b = strfind(s, ‘ ‘)
  end
  return s
end

-------------------
8.4 可变个数参数
-------------------
Lua 并没有提供显著的机制去实现可变个数参数。然而,你可以使用表的构造去模拟这个机制。如下面的例子,假设函数想连接它所有的参数。可以采用如下代码:
function concat (o)
  local i = 1
  local s = ‘‘
  while o[i] do
    s = s .. o[i]
    i = i+1
  end
  return s
end
为了调用它,可以使用一个表的构造去连接所有的参数:
x = concat{"hello ", "john", " and ", "mary"}

-------------------
8.5 持久化
-------------------
由于 Lua 的自反性,持久化在 Lua 中可以用 Lua 实现。本节展示一些方法来存储和恢复 Lua 中的值,用 Lua 写成的文本文件作为存储媒介。
保存一个键值对,用下面的代码就可以了:
function store (name, value)
  write(format(‘\n%s =‘, name))
  write_value(value)
end
function write_value (value)
  local t = type(value)
  if t == ‘nil‘ then write(‘nil‘)
  elseif t == ‘number‘ then write(value)
  elseif t == ‘string‘ then write(value, ‘q‘)
  end
end
为了恢复这些值,一个 lua_dofile 就足够了。
存储表有点复杂。假定表是一棵树,所有下标均为标识符(也就是说,表被用作记录),表的值可以用表的构造函数写成。
首先,把函数 write_value 改为
function write_value (value)
  local t = type(value)
  if t == ‘nil‘ then write(‘nil‘)
  elseif t == ‘number‘ then write(value)
  elseif t == ‘string‘ then write(value, ‘q‘)
  elseif t == ‘table‘ then write_record(value)
  end
end
函数 write_record 是:
function write_record(t)
  local i, v = next(t, nil)
  write(‘{‘) -- starts constructor
  while i do
    store(i, v)
    write(‘, ‘)
    i, v = next(t, i)
  end
  write(‘}‘) -- closes constructor
end
-------------------
8.6 继承
-------------------
不存在索引的回退可以用来在 Lua 中实现多种继承。如下例,下面的代码实现了一个单继承:
function Index (t,f)
  if f == ‘parent‘ then -- to avoid loop
    return OldIndex(t,f)
  end
  local p = t.parent
  if type(p) == ‘table‘ then
    return p[f]
  else
    return OldIndex(t,f)
  end
end

OldIndex = setfallback("index", Index)
当 Lua 试图去获得一个表中不存在的字段时,它调用回退函数 Index 。如果表有一个 parent 字段含有表的值,Lua 会试图去从它的 parent 对象获得想要的字段。这个过程重复“向上”直到为那个字段找到一个值或者对象没有 parent。在后面的情况,前面的回退将会被调用去为相应字段提供一个值。
当需要一个更好的性能时,同样的回退可以用 C 实现,如下面的代码中所示。
#include "lua.h"
int lockedParentName; /* lock index for the string "parent" */
int lockedOldIndex; /* previous fallback function */
void callOldFallback (lua_Object table, lua_Object index)
{
  lua_Object oldIndex = lua_getref(lockedOldIndex);
  lua_pushobject(table);
  lua_pushobject(index);
  lua_callfunction(oldIndex);
}
void Index (void)
{
  lua_Object table = lua_getparam(1);
  lua_Object index = lua_getparam(2);
  lua_Object parent;
  if (lua_isstring(index) && strcmp(lua_getstring(index), "parent") == 0)
  {
    callOldFallback(table, index);
    return;
  }
  lua_pushobject(table);
  lua_pushref(lockedParentName);
  parent = lua_getsubscript();
  if (lua_istable(parent))
  {
    lua_pushobject(parent);
    lua_pushobject(index);
    /* return result from getsubscript */
    lua_pushobject(lua_getsubscript());
  }
  else
    callOldFallback(table, index);
}

这个代码必须如下注册:
lua_pushstring("parent");
lockedParentName = lua_ref(1);
lua_pushobject(lua_setfallback("index", Index));
lockedOldIndex = lua_ref(1);
注意为提升性能字符串 "parent" 是如何锁定的。

-------------------
8.7 用类编程
-------------------
在 Lua 中有多种不同的方法进行面向对象编程。这个就展示一种可能实现类的方法,用上面提到的继承机制。注意:下面的例子只在 index 的回退被根据 8.6 重定义后才可以工作。
就像你所预想的那样,一个好的表示类的方法是用表。这个表将包含类的所有实例方法,另外可能的实现变量的默认值。一个类的例子是让它的 parent 的字段指向那个类,所以它“继承”所有的方法。
Point = {x = 0, y = 0}
function Point:create (o)
o.parent = self
return o
end
function Point:move (p)
self.x = self.x + p.x
self.y = self.y + p.y
end
...
--
-- creating points
--
p1 = Point:create{x = 10, y = 20}
p2 = Point:create{x = 10} -- y will be inherited until it is set
--
-- example of a method invocation
--
p1:move(p2)

例如,一个 Point 类可以如上所示。函数 create 帮助新建一个新的 point,添加它的 parent 字段。函数 move 是一个实例方法的例子。最后,一个字类可以新建为一个新表,它的 parent 字段指向它的父类。注意一个有趣的地方是 self 在方法 create 是如何使用的是允许这个方法可以正常工作就算是它被一个子类继承了。像平常的一样,一个字类可以用它自己的方法重写所有它继承的方法。

-------------------
8.8 模块
-------------------
这里我们解释一个可以在 Lua 中模拟模块的方法。主要的想法是使用一个表去保存模拟的函数。
一个模块应该被写为一个单独的块(chunk),开始于:
if modulename then return end -- avoid loading twice the same module
modulename = {} -- create a table to represent the module
之后,函数可以直接由下面的语法定义:
function modulename.foo (...)
...
end
所有需要这些模块的代码只需要执行 dofile("filename"), filename 就是模块定义的文件。之后,任何函数都可以由下面这样调用:
modulename.foo(...)
如果一个模块方法将要被使用很多次,程序可以给它一个局部名字。
因为函数是值,所以这样写就可以:
localname = modulename.foo
最后,一个模块可以打开,给它的所有的函数直接的访问权限,如下代码所示:
function open (mod)
  local n, f = next(mod, nil)
  while n do
    setglobal(n, f)
    n, f = next(mod, n)
  end
end

-------------------
8.9 一个 Cfunction
-------------------
一个 Cfunction 用来计算最大的数字参数可以写成:
void math_max (void)
{
  int i=1; /* number of arguments */
  double d, dmax;
  lua_Object o;
  /* the function must get at least one argument */
  if ((o = lua_getparam(i++)) == LUA_NOOBJECT)
    lua_error ("too few arguments to function `max‘");
  /* and this argument must be a number */
  if (!lua_isnumber(o))
    lua_error ("incorrect argument to function `max‘");
  dmax = lua_getnumber (o);
  /* loops until there is no more arguments */
  while ((o = lua_getparam(i++)) != LUA_NOOBJECT)
  {
    if (!lua_isnumber(o))
      lua_error ("incorrect argument to function `max‘");
    d = lua_getnumber (o);
    if (d > dmax) dmax = d;
  }
  /* push the result to be returned */
  lua_pushnumber (dmax);
}
使用下面的函数注册:
lua_register ("max", math_max);
这个函数就可以由 Lua 调用了,如下:
i = max(4, 5, 10, -34) -- i receives 10

-------------------
8.5 调用 Lua 函数
-------------------
这个例子显示一个 C 函数如何调用一个 8.3 节中展示的 Lua 函数 remove_blanks。
void remove_blanks (char *s)
{
  lua_pushstring(s); /* prepare parameter */
  lua_call("remove_blanks"); /* call Lua function */
  strcpy(s, lua_getstring(lua_getresult(1))); /* copy result back to ‘s‘ */
}
--------------------------------------
鸣谢
--------------------------------------
作者要感谢 CENPES/PETROBROBAS 和 TeCGraf 一起,使用该系统的早期版本,并提出宝贵意见。作者还要感谢 Carlos Henrique Levy,为这个语言起了个名字。Lua 在葡萄牙语里是月亮的意思。
--------------------------------------
其它(略)
--------------------------------------
和之前版本的不兼容及索引。

时间: 2024-10-07 15:33:34

Lua2.4 参考手册(六)的相关文章

Lua2.4 参考手册(一)

说明:这个文档是 Lua2.4 的 doc 目录里的 refman.ps 文件.原文版权归原作者所有,这篇翻译只是作为学习之用.如果翻译有不当之处,请参考原文.-------------------以下是正文-------------------编程语言 Lua2.4 的参考手册 摘要:Lua 是一个扩展程序语言,被设计用做其它程序的配置语言.本文档描述 Lua 编程语言 2.4 版,以及 Lua 程序和宿主 C 程序交互的 API.它还提供了一些使用这些主要特点的例子. -----------

Ogre参考手册(六)3.3 粒子

3.3 粒子Particle 粒子系统脚本可以作为模板,在运行时创建多个粒子系统 粒子系统脚本在初始化时加载,默认为所有公共资源位置(Root::addResourceLocation)下的’.particle’文件.你可以通过ParticleSystemManager::getSingleton().parseAllSources方法加载自定义扩展名的文件类型,或者通过ParticleSystemManager::getSingleton().parseScript解析单个脚本文件 示例: p

Lua2.4 参考手册(五)

(接上篇)--------------------------------------7 调试接口--------------------------------------Lua 没有内置的调试功能.而是借助于函数和钩子(hook)提供了一个特殊接口,可以用来构建不同种类的调试器,分析器(profile)和一些其它的需要解释器内部信息的工具.这个接口在 luadebug.h 文件中声明.-------------------7.1 栈和函数信息-------------------获得解释器栈

Lua2.4 参考手册(四)

(接上篇)--------------------------------------6 预定义的函数和库--------------------------------------Lua 的一组预定义函数虽少但功能强大.他们中大多数提供的功能让语言有一定程度的自反性.一些功能不能通过语言的其它部分模拟也不能通过标准的 Lua API 模拟.其它的只是一些有用的有用通用 API 函数接口. 库,在另一方面,提供了一种通过标准 API 实现的有用的程序.因此,它们并非语言必需的部分,并且作为单独的

Lua2.4 参考手册(三)

(接上篇)--------------------------------------5 API--------------------------------------这节主要描述 Lua 的 API, 也就是宿主程序和库交互的一组 C 函数.API 函数可以分为以下几类:1. 执行 Lua 代码:2. 在 Lua 和 C 之间进行值的转化:3. 操作(读写)Lua 对象:4. 调用 Lua 函数:5. 由 Lua 调用的 C 函数:6. Lua 对象的引用. 所有的 API 都在文件 lu

Lua2.4 参考手册(二)

(接上篇)--------------------------------------4 语言--------------------------------------这节介绍 Lua 的词法,语法和语义. -------------------4.1 词法约定-------------------Lua 是区别大小写的语言.标识符可以是任何字母,数字,下划线组成的字符串,且首字母不可为数字.下面这些是保留的关键字,不可用做标识符:and     do     else     elseif 

EL表达式参考手册

一.EL简介 1.语法结构     ${expression}2.[]与.运算符     EL 提供.和[]两种运算符来存取数据.    当要存取的属性名称中包含一些特殊字符,如.或?等并非字母或数字的符号,就一定要使用 [].例如:        ${user.My-Name}应当改为${user["My-Name"] }    如果要动态取值时,就可以用[]来做,而.无法做到动态取值.例如:        ${sessionScope.user[data]}中data 是一个变量3

JSTL标签参考手册

前言 ========================================================================= JSTL标签库,是日常开发经常使用的,也是众多标签中性能最好的.把常用的内容,放在这里备份一份,随用随查.尽量做到不用查,就可以随手就可以写出来.这算是Java程序员的基本功吧,一定要扎实. JSTL全名为JavaServer Pages Standard Tag Library,目前最新的版本为1.1版.JSTL是由JCP(Java Comm

《HTML参考手册》学习指南

<HTML 参考手册>是学习HTML过程中不可或缺的一个重要工具,配合W3Cschool首页的<HTML教程>相信你一定能很很快学会它的. 一.HTML是什么? HTML(Hyper Text Mark-up Language )即是超文本标记语言,是 WWW 的描述语言,由 Tim Berners-lee提出.通过使用标记标签来描述页面文档结构和表现形式的一种语言,再由浏览器进行解析,然后把结果展示在网页上.HTML标签是网页构成的基础,我们所见到的几乎所有网页都离不开HTML,