Lua 5.3 å‚考手册

作者 Roberto Ierusalimschy, Luiz Henrique de Figueiredo, Waldemar Celes

译者 云风

Lua.org, PUC-Rio ç‰ˆæƒæ‰€æœ‰ © 2015 , 在éµå¾ª Lua license æ¡æ¬¾ä¸‹ï¼Œå¯è‡ªç”±ä½¿ç”¨ã€‚


目录 · 索引 · 中英术语对照表

1 – 简介

Lua 是一门扩展å¼ç¨‹åºè®¾è®¡è¯­è¨€ï¼Œè¢«è®¾è®¡æˆæ”¯æŒé€šç”¨è¿‡ç¨‹å¼ç¼–ç¨‹ï¼Œå¹¶æœ‰ç›¸å…³æ•°æ®æè¿°è®¾æ–½ã€‚ åŒæ—¶å¯¹é¢å‘对象编程ã€å‡½æ•°å¼ç¼–程和数æ®é©±åЍå¼ç¼–程也æä¾›äº†è‰¯å¥½çš„æ”¯æŒã€‚ 它作为一个强大ã€è½»é‡çš„嵌入å¼è„šæœ¬è¯­è¨€ï¼Œå¯ä¾›ä»»ä½•需è¦çš„程åºä½¿ç”¨ã€‚ Lua ç”± clean C(标准 C å’Œ C++ 间共通的å­é›†ï¼‰ 实现æˆä¸€ä¸ªåº“。

作为一门扩展å¼è¯­è¨€ï¼ŒLua 没有 "main" 程åºçš„æ¦‚念: 它åªèƒ½ 嵌入 一个宿主程åºä¸­å·¥ä½œï¼Œ 该宿主程åºè¢«ç§°ä¸º è¢«åµŒå…¥ç¨‹åº æˆ–è€…ç®€ç§° 宿主 。 宿主程åºå¯ä»¥è°ƒç”¨å‡½æ•°æ‰§è¡Œä¸€å°æ®µ Lua 代ç ï¼Œå¯ä»¥è¯»å†™ Lua å˜é‡ï¼Œå¯ä»¥æ³¨å†Œ C 函数让 Lua 代ç è°ƒç”¨ã€‚ ä¾é  C 函数,Lua å¯ä»¥å…±äº«ç›¸åŒçš„语法框架æ¥å®šåˆ¶ç¼–程语言,从而适用ä¸åŒçš„领域。 Lua 的官方å‘布版包å«ä¸€ä¸ªå«åš lua 的宿主程åºç¤ºä¾‹ï¼Œ 它是一个利用 Lua 库实现的完整独立的 Lua 解释器,å¯ç”¨äºŽäº¤äº’å¼åº”用或批处ç†ã€‚

Lua 是一个自由软件,其使用许å¯è¯å†³å®šäº†å®ƒçš„使用过程无需任何担ä¿ã€‚ 本手册所æè¿°çš„实现å¯ä»¥åœ¨ Lua 的官方网站 www.lua.org 找到。

与其它的许多å‚考手册一样,这份文档有些地方比较枯燥。 关于 Lua 背åŽçš„è®¾è®¡æ€æƒ³ï¼Œ å¯ä»¥çœ‹çœ‹ Lua 网站上æä¾›çš„æŠ€æœ¯è®ºæ–‡ã€‚ 至于用 Lua 编程的细节介ç»ï¼Œ 请å‚阅 Roberto 的书,Programming in Lua。

2 – 基本概念

本章æè¿°äº†è¯­è¨€çš„基本概念。

2.1 – 值与类型

Lua 是一门动æ€ç±»åž‹è¯­è¨€ã€‚ è¿™æ„味ç€å˜é‡æ²¡æœ‰ç±»åž‹ï¼›åªæœ‰å€¼æ‰æœ‰ç±»åž‹ã€‚ 语言中ä¸è®¾ç±»åž‹å®šä¹‰ã€‚ 所有的值æºå¸¦è‡ªå·±çš„类型。

Lua 中所有的值都是 一等公民。 è¿™æ„å‘³ç€æ‰€æœ‰çš„值å‡å¯ä¿å­˜åœ¨å˜é‡ä¸­ã€ å½“ä½œå‚æ•°ä¼ é€’给其它函数ã€ä»¥åŠä½œä¸ºè¿”回值。

Lua 中有八ç§åŸºæœ¬ç±»åž‹ï¼š nilã€booleanã€numberã€stringã€functionã€userdata〠thread å’Œ table。 Nil 是值 nil 的类型, 其主è¦ç‰¹å¾å°±æ˜¯å’Œå…¶å®ƒå€¼åŒºåˆ«å¼€ï¼›é€šå¸¸ç”¨æ¥è¡¨ç¤ºä¸€ä¸ªæœ‰æ„义的值ä¸å­˜åœ¨æ—¶çš„状æ€ã€‚ Boolean 是 false 与 true 两个值的类型。 nil å’Œ false 都会导致æ¡ä»¶åˆ¤æ–­ä¸ºå‡ï¼› 而其它任何值都表示为真。 Number 代表了整数和实数(浮点数)。 String 表示一个ä¸å¯å˜çš„字节åºåˆ—。 Lua 对 8 使˜¯å‹å¥½çš„: 字符串å¯ä»¥å®¹çº³ä»»æ„ 8 ä½å€¼ï¼Œ 其中包å«é›¶ ('\0') 。 Lua çš„å­—ç¬¦ä¸²ä¸Žç¼–ç æ— å…³ï¼› 它ä¸å…³å¿ƒå­—符串中具体内容。

number 类型有两ç§å†…部表现方å¼ï¼Œ æ•´æ•° å’Œ 浮点数。 对于何时使用哪ç§å†…部形å¼ï¼ŒLua 有明确的规则, 但它也按需(å‚è§ §3.4.3)作自动转æ¢ã€‚ 因此,程åºå‘˜å¤šæ•°æƒ…况下å¯ä»¥é€‰æ‹©å¿½ç•¥æ•´æ•°ä¸Žæµ®ç‚¹æ•°ä¹‹é—´çš„差异或者å‡è®¾å®Œå…¨æŽ§åˆ¶æ¯ä¸ªæ•°å­—的内部表现方å¼ã€‚ 标准 Lua 使用 64 使•´æ•°å’ŒåŒç²¾åº¦ï¼ˆ64 ä½ï¼‰æµ®ç‚¹æ•°ï¼Œ 但你也å¯ä»¥æŠŠ Lua 编译æˆä½¿ç”¨ 32 使•´æ•°å’Œå•精度(32 ä½ï¼‰æµ®ç‚¹æ•°ã€‚ 以 32 ä½è¡¨ç¤ºæ•°å­—对å°åž‹æœºå™¨ä»¥åŠåµŒå…¥å¼ç³»ç»Ÿç‰¹åˆ«åˆé€‚。 (å‚è§ luaconf.h æ–‡ä»¶ä¸­çš„å® LUA_32BITS 。)

Lua å¯ä»¥è°ƒç”¨ï¼ˆä»¥åŠæ“作)用 Lua 或 C (å‚è§ §3.4.10)编写的函数。 这两ç§å‡½æ•°æœ‰ç»Ÿä¸€ç±»åž‹ function。

userdata 类型å…许将 C 中的数æ®ä¿å­˜åœ¨ Lua å˜é‡ä¸­ã€‚ 用户数æ®ç±»åž‹çš„值是一个内存å—, 有两ç§ç”¨æˆ·æ•°æ®ï¼š å®Œå…¨ç”¨æˆ·æ•°æ® ï¼ŒæŒ‡ä¸€å—ç”± Lua 管ç†çš„内存对应的对象; è½»é‡ç”¨æˆ·æ•°æ® ,则指一个简å•çš„ C 指针。 用户数æ®åœ¨ Lua 中除了赋值与相等性判断之外没有其他预定义的æ“作。 通过使用 元表 ,程åºå‘˜å¯ä»¥ç»™å®Œå…¨ç”¨æˆ·æ•°æ®å®šä¹‰ä¸€ç³»åˆ—çš„æ“作 (å‚è§ §2.4)。 ä½ åªèƒ½é€šè¿‡ C API 而无法在 Lua 代ç ä¸­åˆ›å»ºæˆ–者修改用户数æ®çš„值, è¿™ä¿è¯äº†æ•°æ®ä»…è¢«å®¿ä¸»ç¨‹åºæ‰€æŽ§åˆ¶ã€‚

thread 类型表示了一个独立的执行åºåˆ—,被用于实现å程 (å‚è§ §2.6)。 Lua 的线程与æ“作系统的线程毫无关系。 Lua ä¸ºæ‰€æœ‰çš„ç³»ç»Ÿï¼ŒåŒ…æ‹¬é‚£äº›ä¸æ”¯æŒåŽŸç”Ÿçº¿ç¨‹çš„ç³»ç»Ÿï¼Œæä¾›äº†å程支æŒã€‚

table æ˜¯ä¸€ä¸ªå…³è”æ•°ç»„, 也就是说,这个数组ä¸ä»…仅以数字åšç´¢å¼•,除了 nil å’Œ NaN 之外的所有 Lua 值 都å¯ä»¥åšç´¢å¼•。 (Not a Number 是一个特殊的数字,它用于表示未定义或表示ä¸äº†çš„è¿ç®—结果,比如 0/0。) 表å¯ä»¥æ˜¯ 异构 的; 也就是说,表内å¯ä»¥åŒ…å«ä»»ä½•类型的值( nil 除外)。 任何键的值若为 nil å°±ä¸ä¼šè¢«è®°å…¥è¡¨ç»“构内部。 æ¢è¨€ä¹‹ï¼Œå¯¹äºŽè¡¨å†…ä¸å­˜åœ¨çš„键,都对应ç€å€¼ nil 。

表是 Lua 中唯一的数æ®ç»“构, 它å¯è¢«ç”¨äºŽè¡¨ç¤ºæ™®é€šæ•°ç»„ã€åºåˆ—ã€ç¬¦å·è¡¨ã€é›†åˆã€è®°å½•ã€å›¾ã€æ ‘等等。 对于记录,Lua 使用域å作为索引。 语言æä¾›äº† a.name è¿™æ ·çš„è¯­æ³•ç³–æ¥æ›¿ä»£ a["name"] è¿™ç§å†™æ³•以方便记录这ç§ç»“构的使用。 在 Lua 中有多ç§ä¾¿åˆ©çš„æ–¹å¼åˆ›å»ºè¡¨ï¼ˆå‚è§ §3.4.9)。

我们使用 åºåˆ— 这个术语æ¥è¡¨ç¤ºä¸€ä¸ªç”¨ {1..n} 的正整数集åšç´¢å¼•的表。 这里的éžè´Ÿæ•´æ•° n 被称为该åºåˆ—的长度(å‚è§ §3.4.7)。

和索引一样,表中æ¯ä¸ªåŸŸçš„值也å¯ä»¥æ˜¯ä»»ä½•类型。 需è¦ç‰¹åˆ«æŒ‡å‡ºçš„æ˜¯ï¼šæ—¢ç„¶å‡½æ•°æ˜¯ä¸€ç­‰å…¬æ°‘,那么表的域也å¯ä»¥æ˜¯å‡½æ•°ã€‚ 这样,表就å¯ä»¥æºå¸¦ 方法 了。 (å‚è§ §3.4.11)。

索引一张表的原则éµå¾ªè¯­è¨€ä¸­çš„直接比较规则。 当且仅当 i 与 j直接比较相等时 (å³ä¸é€šè¿‡å…ƒæ–¹æ³•的比较), è¡¨è¾¾å¼ a[i] 与 a[j] 表示了表中相åŒçš„元素。 特别指出:一个å¯ä»¥å®Œå…¨è¡¨ç¤ºä¸ºæ•´æ•°çš„æµ®ç‚¹æ•°å’Œå¯¹åº”的整数相等 (例如:1.0 == 1)。 为了消除歧义,当一个å¯ä»¥å®Œå…¨è¡¨ç¤ºä¸ºæ•´æ•°çš„æµ®ç‚¹æ•°åšä¸ºé”®å€¼æ—¶ï¼Œ 都会被转æ¢ä¸ºå¯¹åº”的整数储存。 例如,当你写 a[2.0] = true 时, 实际被æ’入表中的键是整数 2 。 (å¦ä¸€æ–¹é¢ï¼Œ2 与 "2" 是两个ä¸åŒçš„ Lua 值, 故而它们å¯ä»¥æ˜¯åŒä¸€å¼ è¡¨ä¸­çš„ä¸åŒé¡¹ã€‚)

表ã€å‡½æ•°ã€çº¿ç¨‹ã€ä»¥åŠå®Œå…¨ç”¨æˆ·æ•°æ®åœ¨ Lua 中被称为 对象: å˜é‡å¹¶ä¸çœŸçš„ æŒæœ‰ 它们的值,而仅ä¿å­˜äº†å¯¹è¿™äº›å¯¹è±¡çš„ 引用。 赋值ã€å‚数传递ã€å‡½æ•°è¿”å›žï¼Œéƒ½æ˜¯é’ˆå¯¹å¼•ç”¨è€Œä¸æ˜¯é’ˆå¯¹å€¼çš„æ“ä½œï¼Œ 这些æ“作å‡ä¸ä¼šåšä»»ä½•å½¢å¼çš„éšå¼æ‹·è´ã€‚

库函数 type 用于以字符串形å¼è¿”回给定值的类型。 (å‚è§ §6.1)。

2.2 – 环境与全局环境

åŽé¢åœ¨ §3.2 ä»¥åŠ §3.3.3 会讨论, å¼•ç”¨ä¸€ä¸ªå« var 的自由å字(指在任何层级都未被声明的å字) åœ¨å¥æ³•上都被翻译为 _ENV.var 。 此外,æ¯ä¸ªè¢«ç¼–译的 Lua 代ç å—都会有一个外部的局部å˜é‡å« _ENV (å‚è§ §3.3.2), 因此,_ENV 这个å字永远都ä¸ä¼šæˆä¸ºä¸€ä¸ªä»£ç å—中的自由å字。

在转译那些自由å字时,_ENV æ˜¯å¦æ˜¯é‚£ä¸ªå¤–部的局部å˜é‡æ— æ‰€è°“。 _ENV 和其它你å¯ä»¥ä½¿ç”¨çš„å˜é‡å没有区别。 这里特别指出,你å¯ä»¥å®šä¹‰ä¸€ä¸ªæ–°å˜é‡æˆ–æŒ‡å®šä¸€ä¸ªå‚æ•°å«è¿™ä¸ªå字。 当编译器在转译自由å字时所用到的 _ENV , 指的是你的程åºåœ¨é‚£ä¸ªç‚¹ä¸Šå¯è§çš„那个å为 _ENV çš„å˜é‡ã€‚ (Lua çš„å¯è§æ€§è§„则å‚è§ §3.5)

被 _ENV 用于值的那张表被称为 环境。

Lua ä¿æœ‰ä¸€ä¸ªè¢«ç§°ä¸º 全局环境 特别环境。它被ä¿å­˜åœ¨ C 注册表 (å‚è§ §4.5)的一个特别索引下。 在 Lua 中,全局å˜é‡ _G 被åˆå§‹åŒ–为这个值。 (_G ä¸è¢«å†…部任何地方使用。)

当 Lua 加载一个代ç å—,_ENV 这个上值的默认值就是这个全局环境 (å‚è§ load)。 因此,在默认情况下,Lua 代ç ä¸­æåŠçš„自由å字都指的全局环境中的相关项 (因此,它们也被称为 全局å˜é‡ )。 æ­¤å¤–ï¼Œæ‰€æœ‰çš„æ ‡å‡†åº“éƒ½è¢«åŠ è½½å…¥å…¨å±€çŽ¯å¢ƒï¼Œä¸€äº›å‡½æ•°ä¹Ÿé’ˆå¯¹è¿™ä¸ªçŽ¯å¢ƒåšæ“作。 ä½ å¯ä»¥ç”¨ load (或 loadfile)加载代ç å—,并赋予它们ä¸åŒçš„环境。 (在 C 里,当你加载一个代ç å—åŽï¼Œå¯ä»¥é€šè¿‡æ”¹å˜å®ƒçš„ç¬¬ä¸€ä¸ªä¸Šå€¼æ¥æ”¹å˜å®ƒçš„环境。)

2.3 – 错误处ç†

由于 Lua æ˜¯ä¸€é—¨åµŒå…¥å¼æ‰©å±•è¯­è¨€ï¼Œå…¶æ‰€æœ‰è¡Œä¸ºå‡æºäºŽå®¿ä¸»ç¨‹åºä¸­ C 代ç å¯¹æŸä¸ª Lua 库函数的调用。 (å•独使用 Lua 时,lua 程åºå°±æ˜¯å®¿ä¸»ç¨‹åºã€‚) 所以,在编译或è¿è¡Œ Lua 代ç å—的过程中,无论何时å‘生错误, 控制æƒéƒ½è¿”å›žç»™å®¿ä¸»ï¼Œç”±å®¿ä¸»è´Ÿè´£é‡‡å–æ°å½“的措施(比如打å°é”™è¯¯æ¶ˆæ¯ï¼‰ã€‚

å¯ä»¥åœ¨ Lua 代ç ä¸­è°ƒç”¨ error å‡½æ•°æ¥æ˜¾å¼åœ°æŠ›å‡ºä¸€ä¸ªé”™è¯¯ã€‚ 如果你需è¦åœ¨ Lua 中æ•获这些错误, å¯ä»¥ä½¿ç”¨ pcall 或 xpcall 在 ä¿æŠ¤æ¨¡å¼ ä¸‹è°ƒç”¨ä¸€ä¸ªå‡½æ•°ã€‚

无论何时出现错误,都会抛出一个æºå¸¦é”™è¯¯ä¿¡æ¯çš„ 错误对象 (错误消æ¯ï¼‰ã€‚ Lua 本身åªä¼šä¸ºé”™è¯¯ç”Ÿæˆå­—符串类型的错误对象, 但你的程åºå¯ä»¥ä¸ºé”™è¯¯ç”Ÿæˆä»»ä½•类型的错误对象, 这就看你的 Lua ç¨‹åºæˆ–宿主程åºå¦‚何处ç†è¿™äº›é”™è¯¯å¯¹è±¡ã€‚

使用 xpcall 或 lua_pcall 时, 你应该æä¾›ä¸€ä¸ª 消æ¯å¤„ç†å‡½æ•° 用于错误抛出时调用。 该函数需接收原始的错误消æ¯ï¼Œå¹¶è¿”回一个新的错误消æ¯ã€‚ 它在错误å‘ç”ŸåŽæ ˆå°šæœªå±•开时调用, å› æ­¤å¯ä»¥åˆ©ç”¨æ ˆæ¥æ”¶é›†æ›´å¤šçš„ä¿¡æ¯ï¼Œ 比如通过探知栈æ¥åˆ›å»ºä¸€ç»„栈回溯信æ¯ã€‚ åŒæ—¶ï¼Œè¯¥å¤„ç†å‡½æ•°ä¹Ÿå¤„äºŽä¿æŠ¤æ¨¡å¼ä¸‹ï¼Œæ‰€ä»¥è¯¥å‡½æ•°å†…å‘ç”Ÿçš„é”™è¯¯ä¼šå†æ¬¡è§¦å‘它(递归)。 如果递归太深,Lua 会终止调用并返回一个åˆé€‚的消æ¯ã€‚

2.4 – 元表åŠå…ƒæ–¹æ³•

Lua 中的æ¯ä¸ªå€¼éƒ½å¯ä»¥æœ‰ä¸€ä¸ª 元表。 这个 元表 就是一个普通的 Lua 表, 它用于定义原始值在特定æ“作下的行为。 如果你想改å˜ä¸€ä¸ªå€¼åœ¨ç‰¹å®šæ“作下的行为,你å¯ä»¥åœ¨å®ƒçš„元表中设置对应域。 ä¾‹å¦‚ï¼Œå½“ä½ å¯¹éžæ•°å­—值åšåŠ æ“作时, Lua 会检查该值的元表中的 "__add" 域下的函数。 如果能找到,Lua 则调用这个函数æ¥å®ŒæˆåŠ è¿™ä¸ªæ“作。

在元表中事件的键值是一个åŒä¸‹åˆ’线(__)加事件å的字符串; 键关è”的那些值被称为 元方法。 在上一个例å­ä¸­ï¼Œ__add 就是键值, 对应的元方法是执行加æ“作的函数。

ä½ å¯ä»¥ç”¨ getmetatable 函数 æ¥èŽ·å–任何值的元表。 Lua 使用直接访问的方å¼ä»Žå…ƒè¡¨ä¸­æŸ¥è¯¢å…ƒæ–¹æ³•(å‚è§rawget)。 所以,从对象 o 中获å–事件 ev 的元方法等价于下é¢çš„代ç ï¼š

     rawget(getmetatable(o) or {}, "__ev")

ä½ å¯ä»¥ä½¿ç”¨ setmetatable æ¥æ›¿æ¢ä¸€å¼ è¡¨çš„元表。在 Lua 中,你ä¸å¯ä»¥æ”¹å˜è¡¨ä»¥å¤–其它类型的值的元表 (除éžä½ ä½¿ç”¨è°ƒè¯•库(å‚è§§6.10)); 若想改å˜è¿™äº›éžè¡¨ç±»åž‹çš„值的元表,请使用 C API。

è¡¨å’Œå®Œå…¨ç”¨æˆ·æ•°æ®æœ‰ç‹¬ç«‹çš„元表 (当然,多个表和用户数æ®å¯ä»¥å…±äº«åŒä¸€ä¸ªå…ƒè¡¨ï¼‰ã€‚ 其它类型的值按类型共享元表; 也就是说所有的数字都共享åŒä¸€ä¸ªå…ƒè¡¨ï¼Œ 所有的字符串共享å¦ä¸€ä¸ªå…ƒè¡¨ç­‰ç­‰ã€‚ 默认情况下,值是没有元表的, 但字符串库在åˆå§‹åŒ–的时候为字符串类型设置了元表 (å‚è§ §6.4)。

元表决定了一个对象在数学è¿ç®—ã€ä½è¿ç®—ã€æ¯”较ã€è¿žæŽ¥ã€ å–长度ã€è°ƒç”¨ã€ç´¢å¼•时的行为。 元表还å¯ä»¥å®šä¹‰ä¸€ä¸ªå‡½æ•°ï¼Œå½“表对象或用户数æ®å¯¹è±¡åœ¨åžƒåœ¾å›žæ”¶ (å‚è§§2.5)时调用它。

对于一元æ“作符(å–è´Ÿã€æ±‚长度ã€ä½å), å…ƒæ–¹æ³•è°ƒç”¨çš„æ—¶å€™ï¼Œç¬¬äºŒä¸ªå‚æ•°æ˜¯ä¸ªå“‘å…ƒï¼Œå…¶å€¼ç­‰äºŽç¬¬ä¸€ä¸ªå‚æ•°ã€‚ 这样处ç†ä»…仅是为了简化 Lua 的内部实现 (这样处ç†å¯ä»¥è®©æ‰€æœ‰çš„æ“ä½œéƒ½å’ŒäºŒå…ƒæ“作一致), 这个行为有å¯èƒ½åœ¨å°†æ¥çš„版本中移除。 (使用这个é¢å¤–傿•°çš„行为都是ä¸ç¡®å®šçš„。)

æŽ¥ä¸‹æ¥æ˜¯å…ƒè¡¨å¯ä»¥æŽ§åˆ¶çš„事件的详细列表。 æ¯ä¸ªæ“ä½œéƒ½ç”¨å¯¹åº”çš„äº‹ä»¶åæ¥åŒºåˆ†ã€‚ æ¯ä¸ªäº‹ä»¶çš„é”®å用加有 '__' å‰ç¼€çš„字符串æ¥è¡¨ç¤ºï¼› 例如 "add" æ“作的键å为字符串 "__add"。

2.5 – 垃圾收集

Lua 采用了自动内存管ç†ã€‚ è¿™æ„味ç€ä½ ä¸ç”¨æ“心新创建的对象需è¦çš„内存如何分é…出æ¥ï¼Œ 也ä¸ç”¨è€ƒè™‘在对象ä¸å†è¢«ä½¿ç”¨åŽæ€Žæ ·é‡Šæ”¾å®ƒä»¬æ‰€å ç”¨çš„内存。 Lua è¿è¡Œäº†ä¸€ä¸ª 垃圾收集器 æ¥æ”¶é›†æ‰€æœ‰ 死对象 (å³åœ¨ Lua 中ä¸å¯èƒ½å†è®¿é—®åˆ°çš„对象)æ¥å®Œæˆè‡ªåŠ¨å†…å­˜ç®¡ç†çš„工作。 Lua 中所有用到的内存,如:字符串ã€è¡¨ã€ç”¨æˆ·æ•°æ®ã€å‡½æ•°ã€çº¿ç¨‹ã€ 内部结构等,都æœä»Žè‡ªåŠ¨ç®¡ç†ã€‚

Lua å®žçŽ°äº†ä¸€ä¸ªå¢žé‡æ ‡è®°-æ‰«ææ”¶é›†å™¨ã€‚ å®ƒä½¿ç”¨è¿™ä¸¤ä¸ªæ•°å­—æ¥æŽ§åˆ¶åžƒåœ¾æ”¶é›†å¾ªçŽ¯ï¼š 垃圾收集器间歇率 å’Œ 垃圾收集器步进å€çŽ‡ã€‚ 这两个数字都使用百分数为å•ä½ ï¼ˆä¾‹å¦‚ï¼šå€¼ 100 在内部表示 1 )。

åžƒåœ¾æ”¶é›†å™¨é—´æ­‡çŽ‡æŽ§åˆ¶ç€æ”¶é›†å™¨éœ€è¦åœ¨å¼€å¯æ–°çš„循环å‰è¦ç­‰å¾…多久。 增大这个值会å‡å°‘æ”¶é›†å™¨çš„ç§¯æžæ€§ã€‚ 当这个值比 100 å°çš„æ—¶å€™ï¼Œæ”¶é›†å™¨åœ¨å¼€å¯æ–°çš„循环å‰ä¸ä¼šæœ‰ç­‰å¾…。 设置这个值为 200 就会让收集器等到总内存使用é‡è¾¾åˆ° 之å‰çš„䏤倿—¶æ‰å¼€å§‹æ–°çš„循环。

垃圾收集器步进å€çŽ‡æŽ§åˆ¶ç€æ”¶é›†å™¨è¿ä½œé€Ÿåº¦ç›¸å¯¹äºŽå†…存分é…速度的å€çŽ‡ã€‚ 增大这个值ä¸ä»…会让收集器更加积æžï¼Œè¿˜ä¼šå¢žåŠ æ¯ä¸ªå¢žé‡æ­¥éª¤çš„长度。 ä¸è¦æŠŠè¿™ä¸ªå€¼è®¾å¾—å°äºŽ 100 , é‚£æ ·çš„è¯æ”¶é›†å™¨å°±å·¥ä½œçš„太慢了以至于永远都干ä¸å®Œä¸€ä¸ªå¾ªçŽ¯ã€‚ 默认值是 200 ,这表示收集器以内存分é…的“两å€â€é€Ÿå·¥ä½œã€‚

如果你把步进å€çŽ‡è®¾ä¸ºä¸€ä¸ªéžå¸¸å¤§çš„æ•°å­— (比你的程åºå¯èƒ½ç”¨åˆ°çš„字节数还大 10% ), 收集器的行为就åƒä¸€ä¸ª stop-the-world 收集器。 接ç€ä½ è‹¥æŠŠé—´æ­‡çŽ‡è®¾ä¸º 200 , 收集器的行为就和过去的 Lua 版本一样了: æ¯æ¬¡ Lua ä½¿ç”¨çš„å†…å­˜ç¿»å€æ—¶ï¼Œå°±åšä¸€æ¬¡å®Œæ•´çš„æ”¶é›†ã€‚

ä½ å¯ä»¥é€šè¿‡åœ¨ C 中调用 lua_gc 或在 Lua 中调用 collectgarbage æ¥æ”¹å˜è¿™ä¿©æ•°å­—。 这两个函数也å¯ä»¥ç”¨æ¥ç›´æŽ¥æŽ§åˆ¶æ”¶é›†å™¨ï¼ˆä¾‹å¦‚åœæ­¢å®ƒæˆ–é‡å¯å®ƒï¼‰ã€‚

2.5.1 – 垃圾收集元方法

ä½ å¯ä»¥ä¸ºè¡¨è®¾å®šåžƒåœ¾æ”¶é›†çš„元方法, 对于完全用户数æ®ï¼ˆå‚è§ §2.4), 则需è¦ä½¿ç”¨ C API 。 该元方法被称为 终结器。 终结器å…许你é…åˆ Lua 的垃圾收集器åšä¸€äº›é¢å¤–的资æºç®¡ç†å·¥ä½œ (例如关闭文件ã€ç½‘络或数æ®åº“连接,或是释放一些你自己的内存)。

如果è¦è®©ä¸€ä¸ªå¯¹è±¡ï¼ˆè¡¨æˆ–用户数æ®ï¼‰åœ¨æ”¶é›†è¿‡ç¨‹ä¸­è¿›å…¥ç»ˆç»“æµç¨‹ï¼Œ ä½ å¿…é¡» 标记 它需è¦è§¦å‘终结器。 当你为一个对象设置元表时,若此刻这张元表中用一个以字符串 "__gc" 为索引的域,那么就标记了这个对象需è¦è§¦å‘终结器。 注æ„:如果你给对象设置了一个没有 __gc åŸŸçš„å…ƒè¡¨ï¼Œä¹‹åŽæ‰ç»™å…ƒè¡¨åŠ ä¸Šè¿™ä¸ªåŸŸï¼Œ 那么这个对象是没有被标记æˆéœ€è¦è§¦å‘终结器的。 然而,一旦对象被标记, 你还是å¯ä»¥è‡ªç”±çš„æ”¹å˜å…¶å…ƒè¡¨ä¸­çš„ __gc 域的。

当一个被标记的对象æˆä¸ºäº†åžƒåœ¾åŽï¼Œ 垃圾收集器并ä¸ä¼šç«‹åˆ»å›žæ”¶å®ƒã€‚ å–而代之的是,Lua 会将其置入一个链表。 在收集完æˆåŽï¼ŒLua å°†é历这个链表。 Lua 会检查æ¯ä¸ªé“¾è¡¨ä¸­çš„对象的 __gc å…ƒæ–¹æ³•ï¼šå¦‚æžœæ˜¯ä¸€ä¸ªå‡½æ•°ï¼Œé‚£ä¹ˆå°±ä»¥å¯¹è±¡ä¸ºå”¯ä¸€å‚æ•°è°ƒç”¨å®ƒï¼› å¦åˆ™ç›´æŽ¥å¿½ç•¥å®ƒã€‚

åœ¨æ¯æ¬¡åžƒåœ¾æ”¶é›†å¾ªçŽ¯çš„æœ€åŽé˜¶æ®µï¼Œ 本次循环中检测到的需è¦è¢«å›žæ”¶ä¹‹å¯¹è±¡ï¼Œ å…¶ç»ˆç»“å™¨çš„è§¦å‘æ¬¡åºæŒ‰å½“åˆç»™å¯¹è±¡ä½œéœ€è¦è§¦å‘终结器的标记之次åºçš„逆åºè¿›è¡Œï¼› 这就是说,第一个被调用的终结器是程åºä¸­æœ€åŽä¸€ä¸ªè¢«æ ‡è®°çš„对象所æºçš„那个。 æ¯ä¸ªç»ˆç»“器的è¿è¡Œå¯èƒ½å‘生在执行常规代ç è¿‡ç¨‹ä¸­çš„ä»»æ„一刻。

由于被回收的对象还需è¦è¢«ç»ˆç»“器使用, 该对象(以åŠä»…能通过它访问到的其它对象)一定会被 Lua 夿´»ã€‚ é€šå¸¸ï¼Œå¤æ´»æ˜¯çŸ­æš‚的,对象所属内存会在下一个垃圾收集循环释放。 ç„¶åŽï¼Œè‹¥ç»ˆç»“器åˆå°†å¯¹è±¡ä¿å­˜åŽ»ä¸€äº›å…¨å±€çš„åœ°æ–¹ (例如:放在一个全局å˜é‡é‡Œï¼‰ï¼Œè¿™æ¬¡å¤æ´»å°±æŒç»­ç”Ÿæ•ˆäº†ã€‚ 此外,如果在终结器中对一个正进入终结æµç¨‹çš„å¯¹è±¡å†æ¬¡åšä¸€æ¬¡æ ‡è®°è®©å®ƒè§¦å‘终结器, åªè¦è¿™ä¸ªå¯¹è±¡åœ¨ä¸‹ä¸ªå¾ªçޝ䏭便—§ä¸å¯è¾¾ï¼Œå®ƒçš„终结函数还会å†è°ƒç”¨ä¸€æ¬¡ã€‚ æ— è®ºæ˜¯å“ªç§æƒ…况, 对象所属内存仅在垃圾收集循环中该对象ä¸å¯è¾¾ä¸” 没有被标记æˆéœ€è¦è§¦å‘终结器æ‰ä¼šè¢«é‡Šæ”¾ã€‚

å½“ä½ å…³é—­ä¸€ä¸ªçŠ¶æ€æœºï¼ˆå‚è§ lua_close), Lua 将调用所有被标记了需è¦è§¦å‘终结器对象的终结过程, 其次åºä¸ºæ ‡è®°æ¬¡åºçš„逆åºã€‚ åœ¨è¿™ä¸ªè¿‡ç¨‹ä¸­ï¼Œä»»ä½•ç»ˆç»“å™¨å†æ¬¡æ ‡è®°å¯¹è±¡çš„行为都ä¸ä¼šç”Ÿæ•ˆã€‚

2.5.2 – 弱表

弱表 指内部元素为 弱引用 的表。 垃圾收集器会忽略掉弱引用。 æ¢å¥è¯è¯´ï¼Œå¦‚果一个对象åªè¢«å¼±å¼•用引用到, 垃圾收集器就会回收这个对象。

一张弱表å¯ä»¥æœ‰å¼±é”®æˆ–是弱值,也å¯ä»¥é”®å€¼éƒ½æ˜¯å¼±å¼•用。 嫿œ‰å¼±å€¼çš„表å…许收集器回收它的值,但会阻止收集器回收它的键。 若一张表的键值å‡ä¸ºå¼±å¼•用, 那么收集器å¯ä»¥å›žæ”¶å…¶ä¸­çš„ä»»æ„键和值。 任何情况下,åªè¦é”®æˆ–值的任æ„一项被回收, 相关è”的键值对都会从表中移除。 一张表的元表中的 __mode 域控制ç€è¿™å¼ è¡¨çš„弱属性。 当 __mode 域是一个包å«å­—符 'k' 的字符串时,这张表的所有键皆为弱引用。 当 __mode 域是一个包å«å­—符 'v' 的字符串时,这张表的所有值皆为弱引用。

属性为弱键强值的表也被称为 暂时表。 对于一张暂时表, 它的值是å¦å¯è¾¾ä»…å–决于其对应键是å¦å¯è¾¾ã€‚ 特别注æ„,如果表内的一个键仅仅被其值所关è”引用, 这个键值对将被表内移除。

对一张表的弱属性的修改仅在下次收集循环æ‰ç”Ÿæ•ˆã€‚ 尤其是当你把表由弱改强,Lua 还是有å¯èƒ½åœ¨ä¿®æ”¹ç”Ÿæ•ˆå‰å›žæ”¶è¡¨å†…一些项目。

åªæœ‰é‚£äº›æœ‰æ˜¾å¼æž„造过程的对象æ‰ä¼šä»Žå¼±è¡¨ä¸­ç§»é™¤ã€‚ å€¼ï¼Œä¾‹å¦‚æ•°å­—å’Œè½»é‡ C 函数,ä¸å—垃圾收集器管辖, å› æ­¤ä¸ä¼šä»Žå¼±è¡¨ä¸­ç§»é™¤ (除éžå®ƒä»¬çš„å…³è”项被回收)。 虽然字符串å—垃圾回收器管辖, 但它们没有显å¼çš„æž„造过程,所以也ä¸ä¼šä»Žå¼±è¡¨ä¸­ç§»é™¤ã€‚

å¼±è¡¨é’ˆå¯¹å¤æ´»çš„对象 (指那些正在走终结æµç¨‹ï¼Œä»…能被终结器访问的对象) 有ç€ç‰¹æ®Šçš„行为。 弱值引用的对象,在è¿è¡Œå®ƒä»¬çš„终结器å‰å°±è¢«ç§»é™¤äº†ï¼Œ 而弱键引用的对象则è¦ç­‰åˆ°ç»ˆç»“器è¿è¡Œå®Œæ¯•åŽï¼Œåˆ°ä¸‹æ¬¡æ”¶é›†å½“对象真的被释放时æ‰è¢«ç§»é™¤ã€‚ 这个行为使得终结器è¿è¡Œæ—¶å¾—以访问到由该对象在弱表中所关è”的属性。

å¦‚æžœä¸€å¼ å¼±è¡¨åœ¨å½“æ¬¡æ”¶é›†å¾ªçŽ¯å†…çš„å¤æ´»å¯¹è±¡ä¸­ï¼Œ 那么在下个循环å‰è¿™å¼ è¡¨æœ‰å¯èƒ½æœªè¢«æ­£ç¡®åœ°æ¸…ç†ã€‚

2.6 – å程

Lua 支æŒåç¨‹ï¼Œä¹Ÿå« ååŒå¼å¤šçº¿ç¨‹ã€‚ 一个å程在 Lua 中代表了一段独立的执行线程。 然而,与多线程系统中的线程的区别在于, å程仅在显å¼è°ƒç”¨ä¸€ä¸ªè®©å‡ºï¼ˆyieldï¼‰å‡½æ•°æ—¶æ‰æŒ‚起当å‰çš„æ‰§è¡Œã€‚

调用函数 coroutine.create å¯åˆ›å»ºä¸€ä¸ªå程。 å…¶å”¯ä¸€çš„å‚æ•°æ˜¯è¯¥å程的主函数。 create 函数åªè´Ÿè´£æ–°å»ºä¸€ä¸ªåç¨‹å¹¶è¿”å›žå…¶å¥æŸ„ (一个 thread 类型的对象); 而ä¸ä¼šå¯åŠ¨è¯¥å程。

调用 coroutine.resume 函数执行一个å程。 第一次调用 coroutine.resume æ—¶ï¼Œç¬¬ä¸€ä¸ªå‚æ•°åº”ä¼ å…¥ coroutine.create 返回的线程对象,然åŽå程从其主函数的第一行开始执行。 传递给 coroutine.resume çš„å…¶ä»–å‚æ•°å°†ä½œä¸ºåç¨‹ä¸»å‡½æ•°çš„å‚æ•°ä¼ å…¥ã€‚ å程å¯åЍ之åŽï¼Œå°†ä¸€ç›´è¿è¡Œåˆ°å®ƒç»ˆæ­¢æˆ– 让出。

å程的è¿è¡Œå¯èƒ½è¢«ä¸¤ç§æ–¹å¼ç»ˆæ­¢ï¼š 正常途径是主函数返回 (显å¼è¿”回或è¿è¡Œå®Œæœ€åŽä¸€æ¡æŒ‡ä»¤ï¼‰ï¼› éžæ­£å¸¸é€”径是å‘生了一个未被æ•获的错误。 对于正常结æŸï¼Œ coroutine.resume 将返回 true, 并接上å程主函数的返回值。 当错误å‘生时, coroutine.resume 将返回 false 与错误消æ¯ã€‚

通过调用 coroutine.yield 使åç¨‹æš‚åœæ‰§è¡Œï¼Œè®©å‡ºæ‰§è¡Œæƒã€‚ å程让出时,对应的最近 coroutine.resume 函数会立刻返回,å³ä½¿è¯¥è®©å‡ºæ“作å‘生在内嵌函数调用中 (å³ä¸åœ¨ä¸»å‡½æ•°ï¼Œä½†åœ¨ä¸»å‡½æ•°ç›´æŽ¥æˆ–间接调用的函数内部)。 在å程让出的情况下, coroutine.resume 也会返回 true, 并加上传给 coroutine.yield çš„å‚æ•°ã€‚ 当下次é‡å¯åŒä¸€ä¸ªå程时, å程会接ç€ä»Žè®©å‡ºç‚¹ç»§ç»­æ‰§è¡Œã€‚ 此时,此å‰è®©å‡ºç‚¹å¤„对 coroutine.yield 的调用 会返回,返回值为传给 coroutine.resume çš„ç¬¬ä¸€ä¸ªå‚æ•°ä¹‹å¤–çš„å…¶ä»–å‚æ•°ã€‚

与 coroutine.create 类似, coroutine.wrap 函数也会创建一个å程。 ä¸åŒä¹‹å¤„在于,它ä¸è¿”回å程本身,而是返回一个函数。 调用这个函数将å¯åŠ¨è¯¥å程。 ä¼ é€’ç»™è¯¥å‡½æ•°çš„ä»»ä½•å‚æ•°å‡å½“作 coroutine.resume çš„é¢å¤–傿•°ã€‚ coroutine.wrap 返回 coroutine.resume 的所有返回值,除了第一个返回值(布尔型的错误ç ï¼‰ã€‚ å’Œ coroutine.resume ä¸åŒï¼Œ coroutine.wrap ä¸ä¼šæ•获错误; 而是将任何错误都传播给调用者。

下é¢çš„代ç å±•示了一个å程工作的范例:

     function foo (a)
       print("foo", a)
       return coroutine.yield(2*a)
     end
     
     co = coroutine.create(function (a,b)
           print("co-body", a, b)
           local r = foo(a+1)
           print("co-body", r)
           local r, s = coroutine.yield(a+b, a-b)
           print("co-body", r, s)
           return b, "end"
     end)
     
     print("main", coroutine.resume(co, 1, 10))
     print("main", coroutine.resume(co, "r"))
     print("main", coroutine.resume(co, "x", "y"))
     print("main", coroutine.resume(co, "x", "y"))

当你è¿è¡Œå®ƒï¼Œå°†äº§ç”Ÿä¸‹åˆ—输出:

     co-body 1       10
     foo     2
     main    true    4
     co-body r
     main    true    11      -9
     co-body x       y
     main    true    10      end
     main    false   cannot resume dead coroutine

你也å¯ä»¥é€šè¿‡ C API æ¥åˆ›å»ºåŠæ“作å程: å‚è§å‡½æ•° lua_newthread, lua_resume, ä»¥åŠ lua_yield。

3 – 语言定义

这一章æè¿°äº† Lua çš„è¯æ³•ã€è¯­æ³•å’Œå¥æ³•。 æ¢å¥è¯è¯´ï¼Œæœ¬ç« æè¿°å“ªäº›ç¬¦è®°æ˜¯æœ‰æ•ˆçš„, 它们如何被组åˆèµ·æ¥ï¼Œè¿™äº›ç»„åˆæ–¹å¼æœ‰ä»€ä¹ˆå«ä¹‰ã€‚

å…³äºŽè¯­è¨€çš„æž„æˆæ¦‚念将用常è§çš„æ‰©å±• BNF 表达å¼å†™å‡ºã€‚ 也就是这个样å­ï¼š {a} 表示 0 或多个 a, [a] 表示一个å¯é€‰çš„ a。 å¯ä»¥è¢«åˆ†è§£çš„éžæœ€ç»ˆç¬¦å·ä¼šè¿™æ ·å†™ non-terminal , 关键字会写æˆè¿™æ · kword, 而其它ä¸èƒ½è¢«åˆ†è§£çš„æœ€ç»ˆç¬¦å·åˆ™å†™æˆè¿™æ · ‘=’ 。 完整的 Lua 语法å¯ä»¥åœ¨æœ¬æ‰‹å†Œæœ€åŽä¸€ç«  §9 找到。

3.1 – è¯æ³•约定

Lua 语言的格å¼è‡ªç”±ã€‚ 它会忽略语法元素(符记)间的空格(包括æ¢è¡Œï¼‰å’Œæ³¨é‡Šï¼Œ 仅把它们看作为å字和关键字间的分割符。

Lua 中的 åå­— (也被称为 标识符) å¯ä»¥æ˜¯ç”±éžæ•°å­—打头的任æ„å­—æ¯ä¸‹åˆ’线和数字构æˆçš„字符串。 标识符å¯ç”¨äºŽå¯¹å˜é‡ã€è¡¨çš„域ã€ä»¥åŠæ ‡ç­¾å‘½å。

下列 关键字 是ä¿ç•™çš„,ä¸å¯ç”¨äºŽå字:

     and       break     do        else      elseif    end
     false     for       function  goto      if        in
     local     nil       not       or        repeat    return
     then      true      until     while

Lua 语言对大å°å†™æ•感: and 是一个ä¿ç•™å­—,但 And 与 AND 则是两个ä¸åŒçš„æœ‰æ•ˆå字。 作为一个约定,程åºåº”é¿å…åˆ›å»ºä»¥ä¸‹åˆ’çº¿åŠ ä¸€ä¸ªæˆ–å¤šä¸ªå¤§å†™å­—æ¯æž„æˆçš„åå­— (例如 _VERSION)。

下列字符串是å¦å¤–一些符记:

     +     -     *     /     %     ^     #
     &     ~     |     <<    >>    //
     ==    ~=    <=    >=    <     >     =
     (     )     {     }     [     ]     ::
     ;     :     ,     .     ..    ...

å­—é¢ä¸² å¯ä»¥ç”¨å•引巿ˆ–åŒå¼•å·æ‹¬èµ·ã€‚ å­—é¢ä¸²å†…部å¯ä»¥åŒ…å«ä¸‹åˆ— C 风格的转义串: '\a' (å“铃), '\b' (退格), '\f' (æ¢é¡µï¼‰ï¼Œ '\n' (æ¢è¡Œï¼‰ï¼Œ '\r' (回车), '\t' (横项制表), '\v' (纵å‘制表), '\\' ï¼ˆåæ–œæ ï¼‰ï¼Œ '\"' (åŒå¼•å·ï¼‰ï¼Œ ä»¥åŠ '\'' (å•引å·)。 åœ¨åæ–œæ åŽè·Ÿä¸€ä¸ªçœŸæ­£çš„æ¢è¡Œç­‰ä»·äºŽåœ¨å­—ç¬¦ä¸²ä¸­å†™ä¸€ä¸ªæ¢è¡Œç¬¦ã€‚ 转义串 '\z' 会忽略其åŽçš„一系列空白符,包括æ¢è¡Œï¼› 它在你需è¦å¯¹ä¸€ä¸ªå¾ˆé•¿çš„å­—ç¬¦ä¸²å¸¸é‡æ–­è¡Œä¸ºå¤šè¡Œå¹¶å¸Œæœ›åœ¨æ¯ä¸ªæ–°è¡Œä¿æŒç¼©è¿›æ—¶éžå¸¸æœ‰ç”¨ã€‚

Lua 中的字符串å¯ä»¥ä¿å­˜ä»»æ„ 8 ä½å€¼ï¼Œå…¶ä¸­åŒ…括用 '\0' 表示的 0 。 一般而言,你å¯ä»¥ç”¨å­—符的数字值æ¥è¡¨ç¤ºè¿™ä¸ªå­—符。 æ–¹å¼æ˜¯ç”¨è½¬ä¹‰ä¸² \xXX, 此处的 XX 必须是æ°å¥½ä¸¤ä¸ªå­—符的 16 进制数。 或者你也å¯ä»¥ä½¿ç”¨è½¬ä¹‰ä¸² \ddd , 这里的 ddd 是一到三个å进制数字。 (注æ„ï¼Œå¦‚æžœåœ¨è½¬ä¹‰ç¬¦åŽæŽ¥ç€æ°å·§æ˜¯ä¸€ä¸ªæ•°å­—符å·çš„è¯ï¼Œ 你就必须在这个转义形å¼ä¸­å†™æ»¡ä¸‰ä¸ªæ•°å­—。)

对于用 UTF-8 ç¼–ç çš„ Unicode 字符,你å¯ä»¥ç”¨ 转义符 \u{XXX} æ¥è¡¨ç¤º (这里必须有一对花括å·ï¼‰ï¼Œ 此处的 XXX 是用 16 进制表示的字符编å·ã€‚

å­—é¢ä¸²è¿˜å¯ä»¥ç”¨ä¸€ç§ é•¿æ‹¬å· æ‹¬èµ·æ¥çš„æ–¹å¼å®šä¹‰ã€‚ 我们把两个正的方括å·é—´æ’å…¥ n 个等å·å®šä¹‰ä¸º 第 n 级开长括å·ã€‚ 就是说,0 级开的长括å·å†™ä½œ [[ , 一级开长括å·å†™ä½œ [=[ , 如此等等。 闭长括å·ä¹Ÿä½œç±»ä¼¼å®šä¹‰ï¼› 举个例å­ï¼Œ4 级å的长括å·å†™ä½œ ]====] 。 一个 é•¿å­—é¢ä¸² å¯ä»¥ç”±ä»»ä½•一级的开长括å·å¼€å§‹ï¼Œè€Œç”±ç¬¬ä¸€ä¸ªç¢°åˆ°çš„åŒçº§çš„闭长括å·ç»“æŸã€‚ è¿™ç§æ–¹å¼æè¿°çš„字符串å¯ä»¥åŒ…å«ä»»ä½•东西,当然特定级别的å长括å·é™¤å¤–。 æ•´ä¸ªè¯æ³•分æžè¿‡ç¨‹å°†ä¸å—分行é™åˆ¶ï¼Œä¸å¤„ç†ä»»ä½•转义符,并且忽略掉任何ä¸åŒçº§åˆ«çš„长括å·ã€‚ 其中碰到的任何形å¼çš„æ¢è¡Œä¸²ï¼ˆå›žè½¦ã€æ¢è¡Œã€å›žè½¦åŠ æ¢è¡Œã€æ¢è¡ŒåŠ å›žè½¦ï¼‰ï¼Œéƒ½ä¼šè¢«è½¬æ¢ä¸ºå•个æ¢è¡Œç¬¦ã€‚

å­—é¢ä¸²ä¸­çš„æ¯ä¸ªä¸è¢«ä¸Šè¿°è§„则影å“的字节都呈现为本身。 然而,Lua æ˜¯ç”¨æ–‡æœ¬æ¨¡å¼æ‰“å¼€æºæ–‡ä»¶è§£æžçš„, 一些系统的文件æ“作函数对æŸäº›æŽ§åˆ¶å­—符的处ç†å¯èƒ½æœ‰é—®é¢˜ã€‚ å› æ­¤ï¼Œå¯¹äºŽéžæ–‡æœ¬æ•°æ®ï¼Œç”¨å¼•å·æ‹¬èµ·æ¥å¹¶æ˜¾å¼æŒ‰è½¬ä¹‰ç¬¦è§„则æ¥è¡¨è¿°æ›´å®‰å…¨ã€‚

为了方便起è§ï¼Œ 当一个开长括å·åŽç´§æŽ¥ä¸€ä¸ªæ¢è¡Œç¬¦æ—¶ï¼Œ 这个æ¢è¡Œç¬¦ä¸ä¼šæ”¾åœ¨å­—符串内。 举个例å­ï¼Œå‡è®¾ä¸€ä¸ªç³»ç»Ÿä½¿ç”¨ ASCII ç  ï¼ˆæ­¤æ—¶ 'a' ç¼–ç ä¸º 97 , æ¢è¡Œç¼–ç ä¸º 10 ,'1' ç¼–ç ä¸º 49 ), 下é¢äº”ç§æ–¹å¼æè¿°äº†å®Œå…¨ç›¸åŒçš„字符串:

     a = 'alo\n123"'
     a = "alo\n123\""
     a = '\97lo\10\04923"'
     a = [[alo
     123"]]
     a = [==[
     alo
     123"]==]

æ•°å­—å¸¸é‡ ï¼ˆæˆ–ç§°ä¸º æ•°å­—é‡ï¼‰ å¯ä»¥ç”±å¯é€‰çš„å°æ•°éƒ¨åˆ†å’Œå¯é€‰çš„å为底的指数部分构æˆï¼Œ 指数部分用字符 'e' 或 'E' æ¥æ ‡è®°ã€‚ Lua 也接å—以 0x 或 0X 开头的 16 进制常é‡ã€‚ 16 进制常é‡ä¹ŸæŽ¥å—å°æ•°åŠ æŒ‡æ•°éƒ¨åˆ†çš„å½¢å¼ï¼ŒæŒ‡æ•°éƒ¨åˆ†æ˜¯ä»¥äºŒä¸ºåº•, 用字符 'p' 或 'P' æ¥æ ‡è®°ã€‚ 数字常é‡ä¸­åŒ…å«å°æ•°ç‚¹æˆ–指数部分时,被认为是一个浮点数; å¦åˆ™è¢«è®¤ä¸ºæ˜¯ä¸€ä¸ªæ•´æ•°ã€‚ 䏋颿œ‰ä¸€äº›åˆæ³•的整数常é‡çš„例å­ï¼š

     3   345   0xff   0xBEBADA

ä»¥ä¸‹ä¸ºåˆæ³•的浮点常é‡ï¼š

     3.0     3.1416     314.16e-2     0.31416E1     34e1
     0x0.1E  0xA23p-4   0X1.921FB54442D18P+1

åœ¨å­—ç¬¦ä¸²å¤–çš„ä»»ä½•åœ°æ–¹å‡ºçŽ°ä»¥åŒæ¨ªçº¿ (--) 开头的部分是 注释 。 如果 -- åŽæ²¡æœ‰ç´§è·Ÿç€ä¸€ä¸ªå¼€å¤§æ‹¬å·ï¼Œ 该注释为 短注释, 注释到当å‰è¡Œæœ«æˆªè‡³ã€‚ å¦åˆ™ï¼Œè¿™æ˜¯ä¸€æ®µ 长注释 , 注释区一直维æŒåˆ°å¯¹åº”的闭长括å·ã€‚ 长注释通常用于临时å±è”½æŽ‰ä¸€å¤§æ®µä»£ç ã€‚

3.2 – å˜é‡

å˜é‡æ˜¯å‚¨å­˜å€¼çš„地方。 Lua 中有三ç§å˜é‡ï¼š 全局å˜é‡ã€å±€éƒ¨å˜é‡å’Œè¡¨çš„域。

å•个åå­—å¯ä»¥æŒ‡ä»£ä¸€ä¸ªå…¨å±€å˜é‡ä¹Ÿå¯ä»¥æŒ‡ä»£ä¸€ä¸ªå±€éƒ¨å˜é‡ (或者是一个函数的形å‚,这是一ç§ç‰¹æ®Šå½¢å¼çš„局部å˜é‡ï¼‰ã€‚

	var ::= Name

å字指 §3.1 中定义的标识符。

所有没有显å¼å£°æ˜Žä¸ºå±€éƒ¨å˜é‡ï¼ˆå‚è§ §3.3.7) çš„å˜é‡å都被当åšå…¨å±€å˜é‡ã€‚ 局部å˜é‡æœ‰å…¶ 作用范围 : 局部å˜é‡å¯ä»¥è¢«å®šä¹‰åœ¨å®ƒä½œç”¨èŒƒå›´ä¸­çš„函数自由使用(å‚è§ §3.5)。

在å˜é‡çš„首次赋值之å‰ï¼Œå˜é‡çš„值å‡ä¸º nil。

方括å·è¢«ç”¨æ¥å¯¹è¡¨ä½œç´¢å¼•:

	var ::= prefixexp ‘[’ exp ‘]

对全局å˜é‡ä»¥åŠè¡¨çš„域之访问的å«ä¹‰å¯ä»¥é€šè¿‡å…ƒè¡¨æ¥æ”¹å˜ã€‚ 以索引方å¼è®¿é—®ä¸€ä¸ªå˜é‡ t[i] 等价于 调用 gettable_event(t,i)。 (å‚è§ §2.4 ,有一份完整的关于 gettable_event 函数的说明。 这个函数并没有在 lua 中定义出æ¥ï¼Œä¹Ÿä¸èƒ½åœ¨ lua 中调用。这里我们把æåˆ°å®ƒåªæ˜¯æ–¹ä¾¿è¯´æ˜Žé—®é¢˜ã€‚)

var.Name è¿™ç§è¯­æ³•åªæ˜¯ä¸€ä¸ªè¯­æ³•糖,用æ¥è¡¨ç¤º var["Name"]:

	var ::= prefixexp ‘.’ Name

对全局å˜é‡ x çš„æ“作等价于æ“作 _ENV.x。 由于代ç å—编译的方å¼ï¼Œ _ENV 永远也ä¸å¯èƒ½æ˜¯ä¸€ä¸ªå…¨å±€åå­— (å‚è§ §2.2)。

3.3 – 语å¥

Lua æ”¯æŒæ‰€æœ‰ä¸Ž Pascal 或是 C 类似的常è§å½¢å¼çš„语å¥ï¼Œ 这个集åˆåŒ…括赋值,控制结构,函数调用,还有å˜é‡å£°æ˜Žã€‚

3.3.1 – 语å¥å—

语å¥å—是一个语å¥åºåˆ—ï¼Œå®ƒä»¬ä¼šæŒ‰æ¬¡åºæ‰§è¡Œï¼š

	block ::= {stat}

Lua æ”¯æŒ ç©ºè¯­å¥ï¼Œ ä½ å¯ä»¥ç”¨åˆ†å·åˆ†å‰²è¯­å¥ï¼Œä¹Ÿå¯ä»¥ä»¥åˆ†å·å¼€å§‹ä¸€ä¸ªè¯­å¥å—, 或是连ç€å†™ä¸¤ä¸ªåˆ†å·ï¼š

	stat ::= ‘;

函数调用和赋值语å¥éƒ½å¯èƒ½ä»¥ä¸€ä¸ªå°æ‹¬å·æ‰“头, è¿™å¯èƒ½è®© Lua 的语法产生歧义。 我们æ¥çœ‹çœ‹ä¸‹é¢çš„代ç ç‰‡æ–­ï¼š

     a = b + c
     (print or io.write)('done')

从语法上说,å¯èƒ½æœ‰ä¸¤ç§è§£é‡Šæ–¹å¼ï¼š

     a = b + c(print or io.write)('done')
     
     a = b + c; (print or io.write)('done')

当å‰çš„è§£æžå™¨æ€»æ˜¯ç”¨ç¬¬ä¸€ç§ç»“æž„æ¥è§£æžï¼Œ 它会将开括å·çœ‹æˆå‡½æ•°è°ƒç”¨çš„傿•°ä¼ é€’开始处。 为了é¿å…è¿™ç§äºŒä¹‰æ€§ï¼Œ 在一æ¡è¯­å¥ä»¥å°æ‹¬å·å¼€å¤´æ—¶ï¼Œå‰é¢æ”¾ä¸€ä¸ªåˆ†å·æ˜¯ä¸ªå¥½ä¹ æƒ¯ï¼š

     ;(print or io.write)('done')

一个语å¥å—å¯ä»¥è¢«æ˜¾å¼çš„å®šç•Œä¸ºå•æ¡è¯­å¥ï¼š

	stat ::= do block end

显å¼çš„对一个å—å®šç•Œé€šå¸¸ç”¨æ¥æŽ§åˆ¶å†…éƒ¨å˜é‡å£°æ˜Žçš„作用域。 有时,显å¼å®šç•Œä¹Ÿç”¨äºŽåœ¨ä¸€ä¸ªè¯­å¥å—中间æ’å…¥ return (å‚è§ §3.3.4)。

3.3.2 – 代ç å—

Lua 的一个编译å•元被称为一个 代ç å—。 ä»Žå¥æ³•æž„æˆä¸Šè®²ï¼Œä¸€ä¸ªä»£ç å—就是一个语å¥å—。

	chunk ::= block

Lua 把一个代ç å—当作一个拥有ä¸å®šå‚数的匿å函数 (å‚è§§3.4.11)æ¥å¤„ç†ã€‚ 正是这样,代ç å—内å¯ä»¥å®šä¹‰å±€éƒ¨å˜é‡ï¼Œå®ƒå¯ä»¥æŽ¥æ”¶å‚数,返回若干值。 此外,这个匿å函数在编译时还为它的作用域绑定了一个外部局部å˜é‡ _ENV (å‚è§ §2.2)。 该函数总是把 _ENV 作为它唯一的一个上值, å³ä½¿è¿™ä¸ªå‡½æ•°ä¸ä½¿ç”¨è¿™ä¸ªå˜é‡ï¼Œå®ƒä¹Ÿå­˜åœ¨ã€‚

代ç å—å¯ä»¥è¢«ä¿å­˜åœ¨æ–‡ä»¶ä¸­ï¼Œä¹Ÿå¯ä»¥ä½œä¸ºå®¿ä¸»ç¨‹åºå†…部的一个字符串。 è¦æ‰§è¡Œä¸€ä¸ªä»£ç å—, 首先è¦è®© Lua 加载 它, 将代ç å—中的代ç é¢„编译æˆè™šæ‹Ÿæœºä¸­çš„æŒ‡ä»¤ï¼Œ 而åŽï¼ŒLua 用虚拟机解释器æ¥è¿è¡Œç¼–译åŽçš„代ç ã€‚

代ç å—å¯ä»¥è¢«é¢„编译为二进制形å¼ï¼› å‚è§ç¨‹åº luac 以åŠå‡½æ•° string.dump å¯èŽ·å¾—æ›´å¤šç»†èŠ‚ã€‚ 用æºç è¡¨ç¤ºçš„程åºå’Œç¼–译åŽçš„å½¢å¼å¯è‡ªç”±æ›¿æ¢ï¼› Lua 会自动检测文件格å¼åšç›¸åº”çš„å¤„ç† ï¼ˆå‚è§ load)。

3.3.3 – 赋值

Lua å…许多é‡èµ‹å€¼ã€‚ 因此,赋值的语法定义是等å·å·¦è¾¹æ”¾ä¸€ä¸ªå˜é‡åˆ—表, 而等å·å³è¾¹æ”¾ä¸€ä¸ªè¡¨è¾¾å¼åˆ—表。 两边的列表中的元素都用逗å·é—´å¼€ï¼š

	stat ::= varlist ‘=’ explist
	varlist ::= var {‘,’ var}
	explist ::= exp {‘,’ exp}

è¡¨è¾¾å¼æ”¾åœ¨ §3.4 中讨论。

在作赋值æ“作之å‰ï¼Œ 那值列表会被 调整 为左边å˜é‡åˆ—表的个数。 如果值比需è¦çš„æ›´å¤šçš„è¯ï¼Œå¤šä½™çš„值就被扔掉。 如果值的数é‡ä¸å¤Ÿéœ€æ±‚, 将会按所需扩展若干个 nil。 如果表达å¼åˆ—表以一个函数调用结æŸï¼Œ 这个函数所返回的所有值都会在调整æ“作之å‰è¢«ç½®å…¥å€¼åˆ—表中 (除éžè¿™ä¸ªå‡½æ•°è°ƒç”¨è¢«ç”¨æ‹¬å·æ‹¬äº†èµ·æ¥ï¼›å‚è§ §3.4)。

赋值语å¥é¦–先让所有的表达å¼å®Œæˆè¿ç®—, 之åŽå†åšèµ‹å€¼æ“作。 因此,下é¢è¿™æ®µä»£ç 

     i = 3
     i, a[i] = i+1, 20

会把 a[3] 设置为 20,而ä¸ä¼šå½±å“到 a[4] 。 这是因为 a[i] 中的 i 在被赋值为 4 之å‰å°±è¢«è®¡ç®—出æ¥äº†ï¼ˆå½“时是 3 )。 简å•说 ,这样一行

     x, y = y, x

ä¼šäº¤æ¢ x å’Œ y 的值, åŠ

     x, y, z = y, z, x

ä¼šè½®æ¢ x,y,z 的值。

对全局å˜é‡ä»¥åŠè¡¨çš„域的赋值æ“作的å«ä¹‰å¯ä»¥é€šè¿‡å…ƒè¡¨æ¥æ”¹å˜ã€‚ 对 t[i] = val 这样的å˜é‡ç´¢å¼•赋值, 等价于 settable_event(t,i,val)。 (关于函数 settable_event 的详细说明,å‚è§ §2.4。 这个函数并没有在 Lua 中定义出æ¥ï¼Œä¹Ÿä¸å¯ä»¥è¢«è°ƒç”¨ã€‚ 这里我们列出æ¥ï¼Œä»…仅出于方便解释的目的。)

对于全局å˜é‡ x = val 的赋值等价于 _ENV.x = val (å‚è§ §2.2)。

3.3.4 – 控制结构

if, while, and repeat 这些控制结构符åˆé€šå¸¸çš„æ„ä¹‰ï¼Œè€Œä¸”ä¹Ÿæœ‰ç±»ä¼¼çš„è¯­æ³•ï¼š

	stat ::= while exp do block end
	stat ::= repeat block until exp
	stat ::= if exp then block {elseif exp then block} [else block] end

Lua 也有一个 for 语å¥ï¼Œå®ƒæœ‰ä¸¤ç§å½¢å¼ (å‚è§ §3.3.5)。

控制结构中的æ¡ä»¶è¡¨è¾¾å¼å¯ä»¥è¿”回任何值。 false 与 nil 两者都被认为是å‡ã€‚ 所有ä¸åŒäºŽ nil 与 false 的其它值都被认为是真 ï¼ˆç‰¹åˆ«éœ€è¦æ³¨æ„的是,数字 0 和空字符串也被认为是真)。

在 repeatuntil 循环中, 内部语å¥å—的结æŸç‚¹ä¸æ˜¯åœ¨ until 这个关键字处, 它还包括了其åŽçš„æ¡ä»¶è¡¨è¾¾å¼ã€‚ 因此,æ¡ä»¶è¡¨è¾¾å¼ä¸­å¯ä»¥ä½¿ç”¨å¾ªçŽ¯å†…éƒ¨è¯­å¥å—中的定义的局部å˜é‡ã€‚

goto 语å¥å°†ç¨‹åºçš„æŽ§åˆ¶ç‚¹è½¬ç§»åˆ°ä¸€ä¸ªæ ‡ç­¾å¤„。 ç”±äºŽå¥æ³•上的原因, Lua 里的标签也被认为是语å¥ï¼š

	stat ::= goto Name
	stat ::= label
	label ::= ‘::’ Name ‘::

除了在内嵌函数中,以åŠåœ¨å†…嵌语å¥å—中定义了åŒå标签,的情况外, 标签对于它定义所在的整个语å¥å—å¯è§ã€‚ åªè¦ goto 没有进入一个新的局部å˜é‡çš„作用域,它å¯ä»¥è·³è½¬åˆ°ä»»æ„å¯è§æ ‡ç­¾å¤„。

标签和没有内容的语å¥è¢«ç§°ä¸ºç©ºè¯­å¥ï¼Œå®ƒä»¬ä¸åšä»»ä½•æ“作。

break 被用æ¥ç»“æŸ while〠repeatã€æˆ– for 循环, 它将跳到循环外接ç€ä¹‹åŽçš„语å¥è¿è¡Œï¼š

	stat ::= break

break 跳出最内层的循环。

return 被用于从函数或是代ç å—(其实它就是一个函数) 中返回值。 函数å¯ä»¥è¿”å›žä¸æ­¢ä¸€ä¸ªå€¼ï¼Œæ‰€ä»¥ return 的语法为

	stat ::= return [explist] [‘;’]

return åªèƒ½è¢«å†™åœ¨ä¸€ä¸ªè¯­å¥å—的最åŽä¸€å¥ã€‚ 如果你真的需è¦ä»Žè¯­å¥å—的中间 return, ä½ å¯ä»¥ä½¿ç”¨æ˜¾å¼çš„定义一个内部语å¥å—, 一般写作 do return end。 å¯ä»¥è¿™æ ·å†™æ˜¯å› ä¸ºçŽ°åœ¨ return æˆäº†ï¼ˆå†…部)语å¥å—的最åŽä¸€å¥äº†ã€‚

3.3.5 – For 语å¥

for 有两ç§å½¢å¼ï¼šä¸€ç§æ˜¯æ•°å­—å½¢å¼ï¼Œå¦ä¸€ç§æ˜¯é€šç”¨å½¢å¼ã€‚

æ•°å­—å½¢å¼çš„ for 循环,通过一个数学è¿ç®—䏿–­åœ°è¿è¡Œå†…部的代ç å—。 䏋颿˜¯å®ƒçš„语法:

	stat ::= for Name ‘=’ exp ‘,’ exp [‘,’ exp] do block end

block 将把 name 作循环å˜é‡ã€‚ 从第一个 exp 开始起,直到第二个 exp 的值为止, 其步长为第三个 exp 。 更确切的说,一个 for å¾ªçŽ¯çœ‹èµ·æ¥æ˜¯è¿™ä¸ªæ ·å­

     for v = e1, e2, e3 do block end

这等价于代ç ï¼š

     do
       local var, limit, step = tonumber(e1), tonumber(e2), tonumber(e3)
       if not (var and limit and step) then error() end
       var = var - step
       while true do
         var = var + step
         if (step >= 0 and var > limit) or (step < 0 and var < limit) then
           break
         end
         local v = var
         block
       end
     end

注æ„下é¢è¿™å‡ ç‚¹ï¼š

通用形å¼çš„ for 通过一个å«ä½œ 迭代器 的函数工作。 æ¯æ¬¡è¿­ä»£ï¼Œè¿­ä»£å™¨å‡½æ•°éƒ½ä¼šè¢«è°ƒç”¨ä»¥äº§ç”Ÿä¸€ä¸ªæ–°çš„值, 当这个值为 nil æ—¶ï¼Œå¾ªçŽ¯åœæ­¢ã€‚ 通用形å¼çš„ for 循环的语法如下:

	stat ::= for namelist in explist do block end
	namelist ::= Name {‘,’ Name}

这样的 for 语å¥

     for var_1, ···, var_n in explist do block end

它等价于这样一段代ç ï¼š

     do
       local f, s, var = explist
       while true do
         local var_1, ···, var_n = f(s, var)
         if var_1 == nil then break end
         var = var_1
         block
       end
     end

注æ„以下几点:

3.3.6 – 函数调用语å¥

为了å…许使用函数的副作用, 函数调用å¯ä»¥è¢«ä½œä¸ºä¸€ä¸ªè¯­å¥æ‰§è¡Œï¼š

	stat ::= functioncall

åœ¨è¿™ç§æƒ…况下,所有的返回值都被èˆå¼ƒã€‚ 函数调用在 §3.4.10 中解释。

3.3.7 – 局部声明

局部å˜é‡å¯ä»¥åœ¨è¯­å¥å—中任何地方声明。 声明å¯ä»¥åŒ…å«ä¸€ä¸ªåˆå§‹åŒ–赋值æ“作:

	stat ::= local namelist [‘=’ explist]

如果有åˆå§‹åŒ–值的è¯ï¼Œåˆå§‹åŒ–赋值æ“作的语法和赋值æ“作一致 (å‚è§ §3.3.3 )。 若没有åˆå§‹åŒ–值,所有的å˜é‡éƒ½è¢«åˆå§‹åŒ–为 nil。

一个代ç å—åŒæ—¶ä¹Ÿæ˜¯ä¸€ä¸ªè¯­å¥å—(å‚è§ §3.3.2), 所以局部å˜é‡å¯ä»¥æ”¾åœ¨ä»£ç å—ä¸­é‚£äº›æ˜¾å¼æ³¨æ˜Žçš„语å¥å—之外。

局部å˜é‡çš„å¯è§æ€§è§„则在 §3.5 中解释。

3.4 – 表达å¼

Lua 中有这些基本表达å¼ï¼š

	exp ::= prefixexp
	exp ::= nil | false | true
	exp ::= Numeral
	exp ::= LiteralString
	exp ::= functiondef
	exp ::= tableconstructor
	exp ::= ‘...’
	exp ::= exp binop exp
	exp ::= unop exp
	prefixexp ::= var | functioncall | ‘(’ exp ‘)

数字和字é¢ä¸²åœ¨ §3.1 中解释; å˜é‡åœ¨ §3.2 中解释; 函数定义在 §3.4.11 中解释; 函数调用在 §3.4.10 中解释; 表的构造在 §3.4.9 中解释。 å¯å˜å‚数的表达å¼å†™ä½œä¸‰ä¸ªç‚¹ï¼ˆ'...'), 它åªèƒ½åœ¨æœ‰å¯å˜å‚数的函数中直接使用;这些在 §3.4.11 中解释。

二元æ“ä½œç¬¦åŒ…å«æœ‰æ•°å­¦è¿ç®—æ“作符(å‚è§ §3.4.1), 使“作符(å‚è§ §3.4.2), 比较æ“作符(å‚è§ §3.4.4), 逻辑æ“作符(å‚è§ §3.4.5), 以åŠè¿žæŽ¥æ“作符(å‚è§ §3.4.6)。 一元æ“作符包括负å·ï¼ˆå‚è§ §3.4.1), 按ä½éžï¼ˆå‚è§ §3.4.2), 逻辑éžï¼ˆå‚è§ §3.4.5), å’Œå–长度æ“作符(å‚è§ §3.4.7)。

函数调用和å¯å˜å‚数表达å¼éƒ½å¯ä»¥æ”¾åœ¨å¤šé‡è¿”回值中。 如果函数调用被当作一æ¡è¯­å¥ï¼ˆå‚è§ §3.3.6), å…¶è¿”å›žå€¼åˆ—è¡¨è¢«è°ƒæ•´ä¸ºé›¶ä¸ªå…ƒç´ ï¼Œå³æŠ›å¼ƒæ‰€æœ‰çš„è¿”å›žå€¼ã€‚ 如果表达å¼è¢«ç”¨äºŽè¡¨è¾¾å¼åˆ—表的最åŽï¼ˆæˆ–是唯一的)一个元素, 那么ä¸ä¼šåšä»»ä½•调整(除éžè¡¨è¾¾å¼è¢«æ‹¬å·æ‹¬èµ·æ¥ï¼‰ã€‚ 在其它情况下, Lua 都会把结果调整为一个元素置入表达å¼åˆ—表中, å³ä¿ç•™ç¬¬ä¸€ä¸ªç»“果而忽略之åŽçš„æ‰€æœ‰å€¼ï¼Œæˆ–是在没有结果时, è¡¥å•个 nil。

这里有一些例å­ï¼š

     f()                -- 调整为 0 个结果
     g(f(), x)          -- f() 会被调整为一个结果
     g(x, f())          -- g 收到 x ä»¥åŠ f() 返回的所有结果
     a,b,c = f(), x     -- f() 被调整为 1 个结果 (c 收到 nil)
     a,b = ...          -- a 收到å¯å˜å‚æ•°åˆ—è¡¨çš„ç¬¬ä¸€ä¸ªå‚æ•°ï¼Œ
                        -- b æ”¶åˆ°ç¬¬äºŒä¸ªå‚æ•°ï¼ˆå¦‚æžœå¯å˜å‚数列表中
                        -- æ²¡æœ‰å®žé™…çš„å‚æ•°ï¼Œa å’Œ b 都会收到 nil)
     
     a,b,c = x, f()     -- f() 被调整为 2 个结果
     a,b,c = f()        -- f() 被调整为 3 个结果
     return f()         -- 返回 f() 的所有返回结果
     return ...         -- 返回从å¯å˜å‚æ•°åˆ—è¡¨ä¸­æŽ¥æ”¶åˆ°çš„æ‰€æœ‰å‚æ•°parameters
     return x,y,f()     -- 返回 x, y, ä»¥åŠ f() 的所有返回值
     {f()}              -- 用 f() 的所有返回值创建一个列表
     {...}              -- 用å¯å˜å‚数中的所有值创建一个列表
     {f(), nil}         -- f() 被调整为一个结果

è¢«æ‹¬å·æ‹¬èµ·æ¥çš„è¡¨è¾¾å¼æ°¸è¿œè¢«å½“作一个值。 所以, (f(x,y,z)) å³ä½¿ f 返回多个值, è¿™ä¸ªè¡¨è¾¾å¼æ°¸è¿œæ˜¯ä¸€ä¸ªå•一值。 ((f(x,y,z)) 的值是 f 返回的第一个值。 如果 f ä¸è¿”回值的è¯ï¼Œé‚£ä¹ˆå®ƒçš„值就是 nil 。)

3.4.1 – æ•°å­¦è¿ç®—æ“作符

Lua 支æŒä¸‹åˆ—æ•°å­¦è¿ç®—æ“作符:

除了乘方和浮点除法è¿ç®—, æ•°å­¦è¿ç®—按如下方å¼å·¥ä½œï¼š 如果两个æ“作数都是整数, 该æ“ä½œä»¥æ•´æ•°æ–¹å¼æ“作且结果也将是一个整数。 å¦åˆ™ï¼Œå½“两个æ“作数都是数字或å¯ä»¥è¢«è½¬æ¢ä¸ºæ•°å­—的字符串 (å‚è§ §3.4.3)时, æ“ä½œæ•°ä¼šè¢«è½¬æ¢æˆä¸¤ä¸ªæµ®ç‚¹æ•°ï¼Œ æ“作按通常的浮点规则(一般éµå¾ª IEEE 754 标准) æ¥è¿›è¡Œï¼Œç»“果也是一个浮点数。

乘方和浮点除法 (/) 总是把æ“ä½œæ•°è½¬æ¢æˆæµ®ç‚¹æ•°è¿›è¡Œï¼Œå…¶ç»“果总是浮点数。 乘方使用 ISO C 函数 pow, 因此它也å¯ä»¥æŽ¥å—éžæ•´æ•°çš„æŒ‡æ•°ã€‚

å‘䏋喿•´çš„除法 (//) 指åšä¸€æ¬¡é™¤æ³•,并将商圆整到é è¿‘负无穷的一侧, å³å¯¹æ“作数åšé™¤æ³•åŽå– floor 。

å–æ¨¡è¢«å®šä¹‰æˆé™¤æ³•的余数,其商被圆整到é è¿‘负无穷的一侧(å‘䏋喿•´çš„除法)。

对于整数数学è¿ç®—的溢出问题, 这些æ“作采å–的策略是按通常éµå¾ªçš„以 2 为补ç çš„æ•°å­¦è¿ç®—çš„ 环绕 规则。 (æ¢å¥è¯è¯´ï¼Œå®ƒä»¬è¿”回其è¿ç®—的数学结果对 264 å–æ¨¡åŽçš„æ•°å­—。)

3.4.2 – 使“作符

Lua 支æŒä¸‹åˆ—使“作符:

æ‰€æœ‰çš„ä½æ“作都将æ“作数先转æ¢ä¸ºæ•´æ•° (å‚è§ §3.4.3), ç„¶åŽæŒ‰ä½æ“作,其结果是一个整数。

对于å³ç§»å’Œå·¦ç§»ï¼Œå‡ç”¨é›¶æ¥å¡«è¡¥ç©ºä½ã€‚ ç§»åŠ¨çš„ä½æ•°è‹¥ä¸ºè´Ÿï¼Œåˆ™å‘åæ–¹å‘ä½ç§»ï¼› è‹¥ç§»åŠ¨çš„ä½æ•°çš„ç»å¯¹å€¼å¤§äºŽç­‰äºŽ æ•´æ•°æœ¬èº«çš„ä½æ•°ï¼Œå…¶ç»“果为零 (所有ä½éƒ½è¢«ç§»å‡ºï¼‰ã€‚

3.4.3 – 强制转æ¢

Lua 对一些类型和值的内部表示会在è¿è¡Œæ—¶åšä¸€äº›æ•°å­¦è½¬æ¢ã€‚ 使“作总是将浮点æ“ä½œæ•°è½¬æ¢æˆæ•´æ•°ã€‚ 乘方和浮点除法总是将整数转æ¢ä¸ºæµ®ç‚¹æ•°ã€‚ 其它数学æ“ä½œè‹¥é’ˆå¯¹æ··åˆæ“作数 (整数和浮点数)将把整数转æ¢ä¸ºæµ®ç‚¹æ•°ï¼› 这一点被称为 通常规则。 C API åŒæ ·ä¼šæŒ‰éœ€æŠŠæ•´æ•°è½¬æ¢ä¸ºæµ®ç‚¹æ•°ä»¥åŠ æŠŠæµ®ç‚¹æ•°è½¬æ¢ä¸ºæ•´æ•°ã€‚ 此外,字符串连接æ“作除了字符串,也å¯ä»¥æŽ¥å—æ•°å­—ä½œä¸ºå‚æ•°ã€‚

当æ“ä½œéœ€è¦æ•°å­—时,Lua 还会把字符串转æ¢ä¸ºæ•°å­—。

当把一个整数转æ¢ä¸ºæµ®ç‚¹æ•°æ—¶ï¼Œ 若整数值æ°å¥½å¯ä»¥è¡¨ç¤ºä¸ºä¸€ä¸ªæµ®ç‚¹æ•°ï¼Œé‚£å°±å–那个浮点数。 å¦åˆ™ï¼Œè½¬æ¢ä¼šå–最接近的较大值或较å°å€¼æ¥è¡¨ç¤ºè¿™ä¸ªæ•°ã€‚ è¿™ç§è½¬æ¢æ˜¯ä¸ä¼šå¤±è´¥çš„。

将浮点数转为整数的过程会检查 浮点数能å¦è¢«å‡†ç¡®çš„表达为一个整数 (å³ï¼Œæµ®ç‚¹æ•°æ˜¯ä¸€ä¸ªæ•´æ•°å€¼ä¸”在整数å¯ä»¥è¡¨è¾¾çš„区间)。 如果å¯ä»¥ï¼Œç»“果就是那个数,å¦åˆ™è½¬æ¢å¤±è´¥ã€‚

从字符串到数字的转æ¢è¿‡ç¨‹éµå¾ªä»¥ä¸‹æµç¨‹ï¼š 首先,éµå¾ªæŒ‰ Lua è¯æ³•分æžå™¨çš„规则分æžè¯­æ³•æ¥è½¬æ¢ä¸ºå¯¹åº”çš„ 整数或浮点数。 (字符串å¯ä»¥æœ‰å‰ç½®æˆ–åŽç½®çš„空格以åŠä¸€ä¸ªç¬¦å·ã€‚) ç„¶åŽï¼Œç»“æžœæ•°å­—å†æŒ‰å‰è¿°è§„则转æ¢ä¸ºæ‰€éœ€è¦çš„类型(浮点或整数)。

从数字转æ¢ä¸ºå­—ç¬¦ä¸²ä½¿ç”¨éžæŒ‡å®šçš„人å¯è¯»çš„æ ¼å¼ã€‚ 若想完全控制数字到字符串的转æ¢è¿‡ç¨‹ï¼Œ å¯ä»¥ä½¿ç”¨å­—符串库中的 format 函数 (å‚è§ string.format)。

3.4.4 – 比较æ“作符

Lua 支æŒä¸‹åˆ—比较æ“作符:

这些æ“ä½œçš„ç»“æžœä¸æ˜¯ false 就是 true。

等于æ“作 (==)先比较æ“作数的类型。 如果类型ä¸åŒï¼Œç»“果就是 false。 å¦åˆ™ï¼Œç»§ç»­æ¯”较值。 å­—ç¬¦ä¸²æŒ‰ä¸€èˆ¬çš„æ–¹å¼æ¯”较。 æ•°å­—éµå¾ªäºŒå…ƒæ“作的规则: 如果两个æ“作数都是整数, 它们按整数比较; å¦åˆ™ï¼Œå®ƒä»¬å…ˆè½¬æ¢ä¸ºæµ®ç‚¹æ•°ï¼Œç„¶åŽå†åšæ¯”è¾ƒã€‚

表,用户数æ®ï¼Œä»¥åŠçº¿ç¨‹éƒ½æŒ‰å¼•用比较: åªæœ‰ä¸¤è€…引用åŒä¸€ä¸ªå¯¹è±¡æ—¶æ‰è®¤ä¸ºå®ƒä»¬ç›¸ç­‰ã€‚ æ¯æ¬¡ä½ åˆ›å»ºä¸€ä¸ªæ–°å¯¹è±¡ï¼ˆä¸€å¼ è¡¨ï¼Œä¸€ä¸ªç”¨æˆ·æ•°æ®ï¼Œæˆ–一个线程), 新对象都一定和已有且存在的对象ä¸åŒã€‚ 相åŒå¼•用的闭包一定相等。 有任何å¯å¯Ÿè§‰çš„差异(ä¸åŒçš„行为,ä¸åŒçš„定义)一定ä¸ç­‰ã€‚

ä½ å¯ä»¥é€šè¿‡ä½¿ç”¨ "eq" 元方法(å‚è§ §2.4) æ¥æ”¹å˜ Lua æ¯”è¾ƒè¡¨å’Œç”¨æˆ·æ•°æ®æ—¶çš„æ–¹å¼ã€‚

等于æ“作ä¸ä¼šå°†å­—符串转æ¢ä¸ºæ•°å­—,å之亦然。 å³ï¼Œ"0"==0 结果为 false, 且 t[0] 与 t["0"] 指代ç€è¡¨ä¸­çš„ä¸åŒé¡¹ã€‚

~= æ“作完全等价于 (==) æ“作的å值。

大尿¯”较æ“作以以下方å¼è¿›è¡Œã€‚ å¦‚æžœå‚æ•°éƒ½æ˜¯æ•°å­—, 它们按二元æ“作的常规进行。 å¦åˆ™ï¼Œå¦‚æžœä¸¤ä¸ªå‚æ•°éƒ½æ˜¯å­—符串, 它们的值按当å‰çš„åŒºåŸŸè®¾ç½®æ¥æ¯”较。 å†åˆ™ï¼ŒLua 就试ç€è°ƒç”¨ "lt" 或是 "le" 元方法 (å‚è§ §2.4)。 a > b 的比较被转译为 b < a, a >= b 被转译为 b <= a。

3.4.5 – 逻辑æ“作符

Lua 中的逻辑æ“作符有 and, orï¼Œä»¥åŠ not。 和控制结构(å‚è§ §3.3.4)一样, 所有的逻辑æ“作符把 false å’Œ nil 都作为å‡ï¼Œ 而其它的一切都当作真。

å–åæ“ä½œ not 总是返回 false 或 true 中的一个。 与æ“作符 and åœ¨ç¬¬ä¸€ä¸ªå‚æ•°ä¸º false 或 nil æ—¶ è¿”å›žè¿™ç¬¬ä¸€ä¸ªå‚æ•°ï¼› å¦åˆ™ï¼Œand è¿”å›žç¬¬äºŒä¸ªå‚æ•°ã€‚ 或æ“作符 or åœ¨ç¬¬ä¸€ä¸ªå‚æ•°ä¸ä¸º nil 也ä¸ä¸º false 时, è¿”å›žè¿™ç¬¬ä¸€ä¸ªå‚æ•°ï¼Œå¦åˆ™è¿”å›žç¬¬äºŒä¸ªå‚æ•°ã€‚ and å’Œ or 都éµå¾ªçŸ­è·¯è§„则; 也就是说,第二个æ“作数åªåœ¨éœ€è¦çš„æ—¶å€™åŽ»æ±‚å€¼ã€‚ 这里有一些例å­ï¼š

     10 or 20            --> 10
     10 or error()       --> 10
     nil or "a"          --> "a"
     nil and 10          --> nil
     false and error()   --> false
     false and nil       --> false
     false or nil        --> nil
     10 and 20           --> 20

(在这本手册中, --> 指å‰é¢è¡¨è¾¾å¼çš„结果。)

3.4.6 – 字符串连接

Lua 中字符串的连接æ“作符写作两个点('..')。 如果两个æ“作数都是字符串或都是数字, 连接æ“作将以 §3.4.3 中æåˆ°çš„规则把其转æ¢ä¸ºå­—符串。 å¦åˆ™ï¼Œä¼šè°ƒç”¨å…ƒæ–¹æ³• __concat (å‚è§ §2.4)。

3.4.7 – å–长度æ“作符

å–长度æ“作符写作一元å‰ç½®ç¬¦ #。 字符串的长度是它的字节数(就是以一个字符一个字节计算的字符串长度)。

程åºå¯ä»¥é€šè¿‡ __len 元方法(å‚è§ §2.4) æ¥ä¿®æ”¹å¯¹å­—符串类型外的任何值的å–长度æ“作行为。

如果 __len 元方法没有给出, 表 t 的长度åªåœ¨è¡¨æ˜¯ä¸€ä¸ª åºåˆ— 时有定义。 åºåˆ—指表的正数键集等于 {1..n} , 其中 n 是一个éžè´Ÿæ•´æ•°ã€‚ åœ¨è¿™ç§æƒ…况下,n 是表的长度。 注æ„这样的表

     {10, 20, nil, 40}

䏿˜¯ä¸€ä¸ªåºåˆ—,因为它有键 4 å´æ²¡æœ‰é”® 3。 (因此,该表的正整数键集ä¸ç­‰äºŽ {1..n} 集åˆï¼Œæ•…而就ä¸å­˜åœ¨ n。) 注æ„ï¼Œä¸€å¼ è¡¨æ˜¯å¦æ˜¯ä¸€ä¸ªåºåˆ—å’Œå®ƒçš„éžæ•°å­—键无关。

3.4.8 – 优先级

Lua 中æ“作符的优先级写在下表中,从低到高优先级排åºï¼š

     or
     and
     <     >     <=    >=    ~=    ==
     |
     ~
     &
     <<    >>
     ..
     +     -
     *     /     //    %
     unary operators (not   #     -     ~)
     ^

通常, ä½ å¯ä»¥ç”¨æ‹¬å·æ¥æ”¹å˜è¿ç®—次åºã€‚ 连接æ“作符 ('..') 和乘方æ“作 ('^') 是从å³è‡³å·¦çš„。 其它所有的æ“作都是从左至å³ã€‚

3.4.9 – 表构建

è¡¨æž„é€ å­æ˜¯ä¸€ä¸ªæž„造表的表达å¼ã€‚ æ¯æ¬¡æž„造å­è¢«æ‰§è¡Œï¼Œéƒ½ä¼šæž„造出一张新的表。 构造å­å¯ä»¥è¢«ç”¨æ¥æž„造一张空表, 也å¯ä»¥ç”¨æ¥æž„造一张表并åˆå§‹åŒ–其中的一些域。 一般的构造å­çš„语法如下

	tableconstructor ::= ‘{’ [fieldlist] ‘}’
	fieldlist ::= field {fieldsep field} [fieldsep]
	field ::= ‘[’ exp ‘]’ ‘=’ exp | Name ‘=’ exp | exp
	fieldsep ::= ‘,’ | ‘;

æ¯ä¸ªå½¢å¦‚ [exp1] = exp2 的域å‘表中增加新的一项, 其键为 exp1 而值为 exp2。 形如 name = exp 的域等价于 ["name"] = exp。 最åŽï¼Œå½¢å¦‚ exp 的域等价于 [i] = exp , 这里的 i 是一个从 1 开始䏿–­å¢žé•¿çš„æ•°å­—。 这这个格å¼ä¸­çš„其它域ä¸ä¼šç ´å其记数。 举个例å­ï¼š

     a = { [f(1)] = g; "x", "y"; x = 1, f(x), [30] = 23; 45 }

等价于

     do
       local t = {}
       t[f(1)] = g
       t[1] = "x"         -- 1st exp
       t[2] = "y"         -- 2nd exp
       t.x = 1            -- t["x"] = 1
       t[3] = f(x)        -- 3rd exp
       t[30] = 23
       t[4] = 45          -- 4th exp
       a = t
     end

构造å­ä¸­èµ‹å€¼çš„æ¬¡åºæœªå®šä¹‰ã€‚ (次åºé—®é¢˜åªä¼šå¯¹é‚£äº›é”®é‡å¤æ—¶çš„æƒ…况有影å“。)

如果表å•中最åŽä¸€ä¸ªåŸŸçš„形弿˜¯ exp , è€Œä¸”å…¶è¡¨è¾¾å¼æ˜¯ä¸€ä¸ªå‡½æ•°è°ƒç”¨æˆ–者是一个å¯å˜å‚数, é‚£ä¹ˆè¿™ä¸ªè¡¨è¾¾å¼æ‰€æœ‰çš„è¿”å›žå€¼å°†ä¾æ¬¡è¿›å…¥åˆ—表 (å‚è§ §3.4.10)。

åˆå§‹åŒ–域表å¯ä»¥åœ¨æœ€åŽå¤šä¸€ä¸ªåˆ†å‰²ç¬¦ï¼Œ 这样设计å¯ä»¥æ–¹ä¾¿ç”±æœºå™¨ç”Ÿæˆä»£ç ã€‚

3.4.10 – 函数调用

Lua 中的函数调用的语法如下:

	functioncall ::= prefixexp args

函数调用时, 第一步,prefixexp å’Œ args 先被求值。 如果 prefixexp 的值的类型是 function, é‚£ä¹ˆè¿™ä¸ªå‡½æ•°å°±è¢«ç”¨ç»™å‡ºçš„å‚æ•°è°ƒç”¨ã€‚ å¦åˆ™ prefixexp 的元方法 "call" 就被调用, ç¬¬ä¸€ä¸ªå‚æ•°æ˜¯ prefixexp 的值, 接下æ¥çš„æ˜¯åŽŸæ¥çš„è°ƒç”¨å‚æ•° (å‚è§ §2.4)。

这样的形å¼

	functioncall ::= prefixexp ‘:’ Name args

å¯ä»¥ç”¨æ¥è°ƒç”¨ "方法"。 这是 Lua 支æŒçš„一ç§è¯­æ³•糖。 åƒ v:name(args) 这个样å­ï¼Œ è¢«è§£é‡Šæˆ v.name(v,args), 这里的 v åªä¼šè¢«æ±‚值一次。

傿•°çš„语法如下:

	args ::= ‘(’ [explist] ‘)’
	args ::= tableconstructor
	args ::= LiteralString

æ‰€æœ‰å‚æ•°çš„è¡¨è¾¾å¼æ±‚值都在函数调用之å‰ã€‚ è¿™æ ·çš„è°ƒç”¨å½¢å¼ f{fields} 是一ç§è¯­æ³•糖用于表示 f({fields})ï¼› è¿™é‡ŒæŒ‡å‚æ•°åˆ—表是一个新创建出æ¥çš„列表。 è€Œè¿™æ ·çš„å½¢å¼ f'string' (或是 f"string" 亦或是 f[[string]]) 也是一ç§è¯­æ³•糖,用于表示 f('string')ï¼› æ­¤æ—¶çš„å‚æ•°åˆ—表是一个å•独的字符串。

return functioncall 这样的调用形å¼å°†è§¦å‘一次 尾调用。 Lua 实现了 完全尾调用(或称为 完全尾递归): 在尾调用中, 被调用的函数é‡ç”¨è°ƒç”¨å®ƒçš„函数的堆栈项。 å› æ­¤ï¼Œå¯¹äºŽç¨‹åºæ‰§è¡Œçš„嵌套尾调用的层数是没有é™åˆ¶çš„。 然而,尾调用将删除调用它的函数的任何调试信æ¯ã€‚ 注æ„,尾调用åªå‘生在特定的语法下, 仅当 return åªæœ‰å•ä¸€å‡½æ•°è°ƒç”¨ä½œä¸ºå‚æ•°æ—¶æ‰å‘生尾调用; è¿™ç§è¯­æ³•使得调用函数的所有结果å¯ä»¥å®Œæ•´åœ°è¿”回。 因此,下é¢è¿™äº›ä¾‹å­éƒ½ä¸æ˜¯å°¾è°ƒç”¨ï¼š

     return (f(x))        -- 返回值被调整为一个
     return 2 * f(x)
     return x, f(x)       -- 追加若干返回值
     f(x); return         -- 返回值全部被èˆå¼ƒ
     return x or f(x)     -- 返回值被调整为一个

3.4.11 – 函数定义

函数定义的语法如下:

	functiondef ::= function funcbody
	funcbody ::= ‘(’ [parlist] ‘)’ block end

å¦å¤–定义了一些语法糖简化函数定义的写法:

	stat ::= function funcname funcbody
	stat ::= local function Name funcbody
	funcname ::= Name {‘.’ Name} [‘:’ Name]

该语å¥

     function f () body end

被转译æˆ

     f = function () body end

该语å¥

     function t.a.b.c.f () body end

被转译æˆ

     t.a.b.c.f = function () body end

该语å¥

     local function f () body end

被转译æˆ

     local f; f = function () body end

è€Œä¸æ˜¯

     local f = function () body end

(这个差别åªåœ¨å‡½æ•°ä½“内需è¦å¼•用 f æ—¶æ‰æœ‰ã€‚)

ä¸€ä¸ªå‡½æ•°å®šä¹‰æ˜¯ä¸€ä¸ªå¯æ‰§è¡Œçš„表达å¼ï¼Œ 执行结果是一个类型为 function 的值。 当 Lua 预编译一个代ç å—时, 代ç å—作为一个函数,整个函数体也就被预编译了。 那么,无论何时 Lua 执行了函数定义, 这个函数本身就进行了 实例化(或者说是 关闭了)。 这个函数的实例(或者说是 闭包)是表达å¼çš„æœ€ç»ˆå€¼ã€‚

å½¢å‚被看作是一些局部å˜é‡ï¼Œ 它们将由实å‚的值æ¥åˆå§‹åŒ–:

	parlist ::= namelist [‘,’ ‘...’] | ‘...

当一个函数被调用, 如果函数并éžä¸€ä¸ª å¯å˜å‚数函数, å³åœ¨å½¢å‚列表的末尾注明三个点 ('...'), 那么实å‚列表就会被调整到形å‚列表的长度。 å˜é•¿å‚数函数ä¸ä¼šè°ƒæ•´å®žå‚列表; å–而代之的是,它将把所有é¢å¤–çš„å‚æ•°æ”¾åœ¨ä¸€èµ·é€šè¿‡ å˜é•¿å‚数表达å¼ä¼ é€’给函数, å…¶å†™æ³•ä¾æ—§æ˜¯ä¸‰ä¸ªç‚¹ã€‚ 这个表达å¼çš„值是一串实å‚值的列表, 看起æ¥å°±è·Ÿä¸€ä¸ªå¯ä»¥è¿”回多个结果的函数一样。 如果一个å˜é•¿å‚æ•°è¡¨è¾¾å¼æ”¾åœ¨å¦ä¸€ä¸ªè¡¨è¾¾å¼ä¸­ä½¿ç”¨ï¼Œ 或是放在å¦ä¸€ä¸²è¡¨è¾¾å¼çš„中间, 那么它的返回值就会被调整为å•个值。 è‹¥è¿™ä¸ªè¡¨è¾¾å¼æ”¾åœ¨äº†ä¸€ç³»åˆ—表达å¼çš„æœ€åŽä¸€ä¸ªï¼Œ å°±ä¸ä¼šåšè°ƒæ•´äº† (除éžè¿™æœ€åŽä¸€ä¸ªå‚数被括å·ç»™æ‹¬äº†èµ·æ¥ï¼‰ã€‚

我们先åšå¦‚下定义,然åŽå†æ¥çœ‹ä¸€ä¸ªä¾‹å­ï¼š

     function f(a, b) end
     function g(a, b, ...) end
     function r() return 1,2,3 end

下é¢çœ‹çœ‹å®žå‚åˆ°å½¢å‚æ•°ä»¥åŠå¯å˜é•¿å‚数的映射关系:

     CALL            PARAMETERS
     
     f(3)             a=3, b=nil
     f(3, 4)          a=3, b=4
     f(3, 4, 5)       a=3, b=4
     f(r(), 10)       a=1, b=10
     f(r())           a=1, b=2
     
     g(3)             a=3, b=nil, ... -->  (nothing)
     g(3, 4)          a=3, b=4,   ... -->  (nothing)
     g(3, 4, 5, 8)    a=3, b=4,   ... -->  5  8
     g(5, r())        a=5, b=1,   ... -->  2  3

结果由 return æ¥è¿”回(å‚è§ §3.3.4)。 å¦‚æžœæ‰§è¡Œåˆ°å‡½æ•°æœ«å°¾ä¾æ—§æ²¡æœ‰é‡åˆ°ä»»ä½• return 语å¥ï¼Œ 函数就ä¸ä¼šè¿”回任何结果。

关于函数å¯è¿”回值的数é‡é™åˆ¶å’Œç³»ç»Ÿæœ‰å…³ã€‚ 这个é™åˆ¶ä¸€å®šå¤§äºŽ 1000 。

å†’å· è¯­æ³•å¯ä»¥ç”¨æ¥å®šä¹‰ 方法, 就是说,函数å¯ä»¥æœ‰ä¸€ä¸ªéšå¼çš„å½¢å‚ self。 因此,如下语å¥

     function t.a.b.c:f (params) body end

是这样一ç§å†™æ³•的语法糖

     t.a.b.c.f = function (self, params) body end

3.5 – å¯è§æ€§è§„则

Lua è¯­è¨€æœ‰è¯æ³•作用范围。 å˜é‡çš„作用范围开始于声明它们之åŽçš„ç¬¬ä¸€ä¸ªè¯­å¥æ®µï¼Œ 结æŸäºŽåŒ…å«è¿™ä¸ªå£°æ˜Žçš„æœ€å†…层语å¥å—的最åŽä¸€ä¸ªéžç©ºè¯­å¥ã€‚ 看下é¢è¿™äº›ä¾‹å­ï¼š

     x = 10                -- 全局å˜é‡
     do                    -- 新的语å¥å—
       local x = x         -- 新的一个 'x', 它的值现在是 10
       print(x)            --> 10
       x = x+1
       do                  -- å¦ä¸€ä¸ªè¯­å¥å—
         local x = x+1     -- åˆä¸€ä¸ª 'x'
         print(x)          --> 12
       end
       print(x)            --> 11
     end
     print(x)              --> 10 (å–到的是全局的那一个)

注æ„这里,类似 local x = x 这样的声明, æ–°çš„ x 正在被声明,但是还没有进入它的作用范围, 所以第二个 x 指å‘的是外é¢ä¸€å±‚çš„å˜é‡ã€‚

å› ä¸ºæœ‰è¿™æ ·ä¸€ä¸ªè¯æ³•作用范围的规则, 局部å˜é‡å¯ä»¥è¢«åœ¨å®ƒçš„作用范围内定义的函数自由使用。 当一个局部å˜é‡è¢«å†…层的函数中使用的时候, 它被内层函数称作 上值,或是 外部局部å˜é‡ã€‚

注æ„ï¼Œæ¯æ¬¡æ‰§è¡Œåˆ°ä¸€ä¸ª local 语å¥éƒ½ä¼šå®šä¹‰å‡ºä¸€ä¸ªæ–°çš„局部å˜é‡ã€‚ 看看这样一个例å­ï¼š

     a = {}
     local x = 20
     for i=1,10 do
       local y = 0
       a[i] = function () y=y+1; return x+y end
     end

这个循环创建了å个闭包(这指å个匿å函数的实例)。 这些闭包中的æ¯ä¸€ä¸ªéƒ½ä½¿ç”¨äº†ä¸åŒçš„ y å˜é‡ï¼Œ 而它们åˆå…±äº«äº†åŒä¸€ä»½ x。

4 – 编程接å£

这个部分æè¿°äº† Lua çš„ C API , 也就是宿主程åºè·Ÿ Lua 通讯用的一组 C 函数。 所有的 API 函数按相关的类型以åŠå¸¸é‡éƒ½å£°æ˜Žåœ¨å¤´æ–‡ä»¶ lua.h 中。

虽然我们说的是“函数â€ï¼Œ 但一部分简å•çš„ API 是以å®çš„å½¢å¼æä¾›çš„ã€‚ 除éžå¦æœ‰è¯´æ˜Žï¼Œ 所有的这些å®éƒ½åªä½¿ç”¨å®ƒä»¬çš„傿•°ä¸€æ¬¡ ï¼ˆé™¤äº†ç¬¬ä¸€ä¸ªå‚æ•°ï¼Œé‚£ä¸€å®šæ˜¯ Lua 状æ€ï¼‰ï¼Œ 因此你ä¸éœ€æ‹…心这些å®çš„展开会引起一些副作用。

C 库中所有的 Lua API 函数都ä¸åŽ»æ£€æŸ¥å‚æ•°æ˜¯å¦ç›¸å®¹åŠæœ‰æ•ˆã€‚ 然而,你å¯ä»¥åœ¨ç¼–译 Lua 时加上打开一个å®å¼€å…³ LUA_USE_APICHECK æ¥æ”¹å˜è¿™ä¸ªè¡Œä¸ºã€‚

4.1 – æ ˆ

Lua 使用一个 虚拟栈 æ¥å’Œ C 互传值。 栈上的的æ¯ä¸ªå…ƒç´ éƒ½æ˜¯ä¸€ä¸ª Lua 值 (nil,数字,字符串,等等)。

无论何时 Lua 调用 C,被调用的函数都得到一个新的栈, 这个栈独立于 C 函数本身的栈,也独立于之å‰çš„ Lua 栈。 它里é¢åŒ…å«äº† Lua 传递给 C å‡½æ•°çš„æ‰€æœ‰å‚æ•°ï¼Œ 而 C 函数则把è¦è¿”回的结果放入这个栈以返回给调用者 (å‚è§ lua_CFunction)。

方便起è§ï¼Œ 所有针对栈的 API 查询æ“作都ä¸ä¸¥æ ¼éµå¾ªæ ˆçš„æ“ä½œè§„åˆ™ã€‚ 而是å¯ä»¥ç”¨ä¸€ä¸ª 索引 æ¥æŒ‡å‘栈上的任何元素: 正的索引指的是栈上的ç»å¯¹ä½ç½®ï¼ˆä»Ž1开始); 负的索引则指从栈顶开始的åç§»é‡ã€‚ 展开æ¥è¯´ï¼Œå¦‚果堆栈有 n 个元素, 那么索引 1 表示第一个元素 (也就是最先被压栈的元素) 而索引 n 则指最åŽä¸€ä¸ªå…ƒç´ ï¼› 索引 -1 也是指最åŽä¸€ä¸ªå…ƒç´  ï¼ˆå³æ ˆé¡¶çš„元素), 索引 -n 是指第一个元素。

4.2 – 栈大å°

当你使用 Lua API 时, 就有责任ä¿è¯åšæ°å½“的调用。 ç‰¹åˆ«éœ€è¦æ³¨æ„的是, 你有责任控制ä¸è¦å †æ ˆæº¢å‡ºã€‚ ä½ å¯ä»¥ä½¿ç”¨ lua_checkstack è¿™ä¸ªå‡½æ•°æ¥æ‰©å¤§å¯ç”¨å †æ ˆçš„尺寸。

无论何时 Lua 调用 C , 它都åªä¿è¯è‡³å°‘有 LUA_MINSTACK 这么多的堆栈空间å¯ä»¥ä½¿ç”¨ã€‚ LUA_MINSTACK 一般被定义为 20 , 因此,åªè¦ä½ ä¸æ˜¯ä¸æ–­çš„æŠŠæ•°æ®åŽ‹æ ˆï¼Œ 通常你ä¸ç”¨å…³å¿ƒå †æ ˆå¤§å°ã€‚

当你调用一个 Lua å‡½æ•°å´æ²¡æœ‰æŒ‡å®šè¦æŽ¥æ”¶å¤šå°‘个返回值时 (å‚è§ lua_call), Lua å¯ä»¥ä¿è¯æ ˆä¸€å®šæœ‰è¶³å¤Ÿçš„ç©ºé—´æ¥æŽ¥æ”¶æ‰€æœ‰çš„è¿”å›žå€¼ï¼Œ 但ä¸ä¿è¯æ­¤å¤–留有é¢å¤–的空间。 因此,在åšäº†ä¸€æ¬¡è¿™æ ·çš„调用åŽï¼Œå¦‚果你需è¦ç»§ç»­åŽ‹æ ˆï¼Œ 则需è¦ä½¿ç”¨ lua_checkstack。

4.3 – æœ‰æ•ˆç´¢å¼•ä¸Žå¯æŽ¥å—索引

API 中的函数若需è¦ä¼ å…¥æ ˆç´¢å¼•,这个索引必须是 有效索引 或是 坿ޥå—索引。

有效索引 指引用栈内真实ä½ç½®çš„索引; å³åœ¨ 1 到栈顶之间的ä½ç½® (1 ≤ abs(index) ≤ top)。 通常,一个å¯èƒ½ä¿®æ”¹è¯¥ä½ç½®çš„值的函数需è¦ä¼ å…¥æœ‰æ•ˆç´¢å¼•。

除éžå¦æœ‰è¯´æ˜Žï¼Œ 任何å¯ä»¥æŽ¥å—æœ‰æ•ˆç´¢å¼•çš„å‡½æ•°åŒæ—¶ä¹ŸæŽ¥å— 伪索引。 伪索引指代一些å¯ä»¥è¢« C code 访问得到 Lua 值,而它们åˆä¸åœ¨æ ˆå†…。 è¿™ç”¨äºŽè®¿é—®æ³¨å†Œè¡¨ä»¥åŠ C 函数的上值(å‚è§ §4.4)。

å¯¹äºŽé‚£äº›åªæ˜¯éœ€è¦æ ˆä¸­çš„值(例如查询函数) 而ä¸éœ€è¦æŒ‡å®šä¸€ä¸ªæ ˆä½ç½®çš„函数, å¯ä»¥ç”¨ä¸€ä¸ªå¯æŽ¥å—的索引去调用它们。 坿ޥå—索引 ä¸ä»…å¯ä»¥æ˜¯ä»»ä½•包括伪索引在内的有效索引, 还å¯ä»¥æ˜¯ä»»ä½•超过栈顶但è½åœ¨ä¸ºæ ˆåˆ†é…出æ¥çš„空间内的正索引。 ï¼ˆæ³¨æ„ 0 æ°¸è¿œéƒ½ä¸æ˜¯ä¸€ä¸ªå¯æŽ¥å—索引。) 除éžå¦æœ‰è¯´æ˜Žï¼ŒAPI 里的函数都接å—坿ޥå—索引。

å…è®¸å¯æŽ¥å—索引是为了é¿å…对栈顶以外的查询时åšé¢å¤–的检查。 例如,C 函数å¯ä»¥ç›´æŽ¥æŸ¥è¯¢ä¼ ç»™å®ƒçš„ç¬¬ä¸‰ä¸ªå‚æ•°ï¼Œ 而ä¸ç”¨å…ˆæ£€æŸ¥æ˜¯ä¸æ˜¯æœ‰ç¬¬ä¸‰ä¸ªå‚数, å³ä¸éœ€è¦æ£€æŸ¥ 3 æ˜¯ä¸æ˜¯ä¸€ä¸ªæœ‰æ•ˆç´¢å¼•。

对于那å¯ä»¥æŽ¥å—索引调用的函数, 无效索引被看作包å«äº†ä¸€ä¸ªè™šæ‹Ÿç±»åž‹ LUA_TNONE 的值, 这个值的行为和 nil 一致。

4.4 – C 闭包

当 C 函数被创建出æ¥ï¼Œ 我们有å¯èƒ½ä¼šæŠŠä¸€äº›å€¼å…³è”在一起, 也就是创建一个 C 闭包 (å‚è§ lua_pushcclosure); 这些被关è”èµ·æ¥çš„值被å«åš 上值 , 它们å¯ä»¥åœ¨å‡½æ•°è¢«è°ƒç”¨çš„æ—¶å€™è®¿é—®çš„到。

无论何时去调用 C 函数, 函数的上值都å¯ä»¥ç”¨ä¼ªç´¢å¼•定ä½ã€‚ 我们å¯ä»¥ç”¨ lua_upvalueindex è¿™ä¸ªå®æ¥ç”Ÿæˆè¿™äº›ä¼ªç´¢å¼•。 第一个关è”到函数的值放在 lua_upvalueindex(1) ä½ç½®å¤„ï¼Œä¾æ­¤ç±»æŽ¨ã€‚ 使用 lua_upvalueindex(n) 时, è‹¥ n 大于当å‰å‡½æ•°çš„æ€»ä¸Šå€¼ä¸ªæ•° (但ä¸å¯ä»¥å¤§äºŽ 256ï¼‰ä¼šäº§ç”Ÿä¸€ä¸ªå¯æŽ¥å—的但无效的索引。

4.5 – 注册表

Lua æä¾›äº†ä¸€ä¸ª 注册表, 这是一个预定义出æ¥çš„表, å¯ä»¥ç”¨æ¥ä¿å­˜ä»»ä½• C ä»£ç æƒ³ä¿å­˜çš„ Lua 值。 这个表å¯ä»¥ç”¨æœ‰æ•ˆä¼ªç´¢å¼• LUA_REGISTRYINDEX æ¥å®šä½ã€‚ 任何 C 库都å¯ä»¥åœ¨è¿™å¼ è¡¨é‡Œä¿å­˜æ•°æ®ï¼Œ 为了防止冲çªï¼Œä½ éœ€è¦ç‰¹åˆ«å°å¿ƒçš„选择键å。 一般的用法是,你å¯ä»¥ç”¨ä¸€ä¸ªåŒ…å«ä½ çš„库å的字符串åšä¸ºé”®å, 或者å–你自己 C 对象的地å€ï¼Œä»¥è½»é‡ç”¨æˆ·æ•°æ®çš„å½¢å¼åšé”®ï¼Œ 还å¯ä»¥ç”¨ä½ çš„代ç åˆ›å»ºå‡ºæ¥çš„ä»»æ„ Lua 对象åšé”®ã€‚ 关于å˜é‡å,字符串键å中以下划线加大写字æ¯çš„å字被 Lua ä¿ç•™ã€‚

注册表中的整数键用于引用机制 (å‚è§ luaL_ref), 以åŠä¸€äº›é¢„定义的值。 因此,整数键ä¸è¦ç”¨äºŽåˆ«çš„目的。

当你创建了一个新的 Lua çŠ¶æ€æœºï¼Œ 其中的注册表内就预定义好了几个值。 这些预定义值å¯ä»¥ç”¨æ•´æ•°ç´¢å¼•到, 这些整数以常数形å¼å®šä¹‰åœ¨ lua.h 中。 有下列常数:

4.6 – C 中的错误处ç†

在内部实现中,Lua 使用了 C çš„ longjmp 机制æ¥å¤„ç†é”™è¯¯ã€‚ (如果你使用 C++ 编译,Lua å°†æ¢æˆå¼‚常; 细节请在æºä»£ç ä¸­æœç´¢ LUAI_THROW。) 当 Lua 碰到任何错误 (比如内存分é…错误ã€ç±»åž‹é”™è¯¯ã€è¯­æ³•错误ã€è¿˜æœ‰è¿è¡Œæ—¶é”™è¯¯ï¼‰ 它都会 抛出一个错误出去; 也就是调用一次长跳转。 在 ä¿æŠ¤çŽ¯å¢ƒ 下, Lua 使用 setjmp æ¥è®¾ç½®ä¸€ä¸ªæ¢å¤ç‚¹ï¼› 任何å‘生的错误都会跳转到最近的一个æ¢å¤ç‚¹ã€‚

如果错误å‘ç”Ÿåœ¨ä¿æŠ¤çŽ¯å¢ƒä¹‹å¤–ï¼Œ Lua 会先调用 panic 函数 (å‚è§ lua_atpanic) ç„¶åŽè°ƒç”¨ abort æ¥é€€å‡ºå®¿ä¸»ç¨‹åºã€‚ ä½ çš„ panic 函数åªè¦ä¸è¿”回 (例如:长跳转到你在 Lua 外你自己设置的æ¢å¤ç‚¹ï¼‰ å°±å¯ä»¥ä¸é€€å‡ºç¨‹åºã€‚

panic 函数以错误消æ¯å¤„ç†å™¨ï¼ˆå‚è§ §2.3)的方å¼è¿è¡Œï¼› 错误消æ¯åœ¨æ ˆé¡¶ã€‚ ä¸åŒçš„æ˜¯ï¼Œå®ƒä¸ä¿è¯æ ˆç©ºé—´ã€‚ åšä»»ä½•压栈æ“作å‰ï¼Œpanic å‡½æ•°éƒ½å¿…é¡»å…ˆæ£€æŸ¥æ˜¯å¦æœ‰è¶³å¤Ÿçš„空间 (å‚è§ §4.2)。

大多数 API 函数都有å¯èƒ½æŠ›å‡ºé”™è¯¯ï¼Œ 例如在内存分é…错误时就会抛出。 æ¯ä¸ªå‡½æ•°çš„æ–‡æ¡£éƒ½ä¼šæ³¨æ˜Žå®ƒæ˜¯å¦å¯èƒ½æŠ›å‡ºé”™è¯¯ã€‚

在 C 函数内部,你å¯ä»¥é€šè¿‡è°ƒç”¨ lua_error æ¥æŠ›å‡ºé”™è¯¯ã€‚

4.7 – C 中的让出处ç†

Lua 内部使用 C çš„ longjmp 机制让出一个å程。 因此,如果一个 C 函数 foo 调用了一个 API 函数, 而这个 API 函数让出了(直接或间接调用了让出函数)。 由于 longjmp 会移除 C 栈的栈帧, Lua 就无法返回到 foo 里了。

为了回é¿è¿™ç±»é—®é¢˜ï¼Œ 碰到 API 调用中调用让出时,除了那些抛出错误的 API 外,还æä¾›äº†ä¸‰ä¸ªå‡½æ•°ï¼š lua_yieldk, lua_callk,和 lua_pcallk 。 它们在让出å‘生时,å¯ä»¥ä»Žä¼ å…¥çš„ 延续函数 (å为 k çš„å‚æ•°ï¼‰ç»§ç»­è¿è¡Œã€‚

我们需è¦é¢„设一些术语æ¥è§£é‡Šå»¶ç»­ç‚¹ã€‚ 对于从 Lua 中调用的 C 函数,我们称之为 原函数。 ä»Žè¿™ä¸ªåŽŸå‡½æ•°ä¸­è°ƒç”¨çš„ä¸Šé¢æ‰€è¿°çš„三个 C API 函数我们称之为 被调函数。 被调函数å¯ä»¥ä½¿å½“å‰çº¿ç¨‹è®©å‡ºã€‚ (让出å‘生在被调函数是 lua_yieldk, 或传入 lua_callk 或 lua_pcallk 的函数调用了让出时。)

å‡è®¾æ­£åœ¨è¿è¡Œçš„线程在执行被调函数时让出。 当冿¬¡å»¶ç»­è¿™æ¡çº¿ç¨‹ï¼Œå®ƒå¸Œæœ›ç»§ç»­è¢«è°ƒå‡½æ•°çš„è¿è¡Œã€‚ 然而,被调函数ä¸å¯èƒ½è¿”回到原函数中。 这是因为之å‰çš„让出æ“作破å了 C 栈的栈帧。 作为替代å“,Lua è°ƒç”¨é‚£ä¸ªä½œä¸ºè¢«è°ƒå‡½æ•°å‚æ•°ç»™å‡ºçš„ 延续函数 。 正如其å,延续函数将延续原函数的任务。

下é¢çš„函数会åšä¸€ä¸ªè¯´æ˜Žï¼š

     int original_function (lua_State *L) {
       ...     /* code 1 */
       status = lua_pcall(L, n, m, h);  /* calls Lua */
       ...     /* code 2 */
     }

现在我们想å…许被 lua_pcall è¿è¡Œçš„ Lua 代ç è®©å‡ºã€‚ 首先,我们把函数改写æˆè¿™ä¸ªæ ·å­ï¼š

     int k (lua_State *L, int status, lua_KContext ctx) {
       ...  /* code 2 */
     }
     
     int original_function (lua_State *L) {
       ...     /* code 1 */
       return k(L, lua_pcall(L, n, m, h), ctx);
     }

上é¢çš„代ç ä¸­ï¼Œæ–°å‡½æ•° k 就是一个 延续函数 (函数类型为 lua_KFunction)。 它的工作就是原函数中调用 lua_pcall 之åŽåšçš„那些事情。 现在我们必须通知 Lua 说,你必须在被 lua_pcall 执行的 Lua 代ç å‘生过中断(错误或让出)åŽï¼Œ 还得继续调用 k 。 所以我们还得继续改写这段代ç ï¼ŒæŠŠ lua_pcall æ›¿æ¢æˆ lua_pcallk:

     int original_function (lua_State *L) {
       ...     /* code 1 */
       return k(L, lua_pcallk(L, n, m, h, ctx2, k), ctx1);
     }

注æ„这里那个é¢å¤–的显å¼çš„对延续函数的调用: Lua ä»…åœ¨éœ€è¦æ—¶ï¼Œè¿™å¯èƒ½æ˜¯ç”±é”™è¯¯å¯¼è‡´çš„也å¯èƒ½æ˜¯å‘生了让出而需è¦ç»§ç»­è¿è¡Œï¼Œæ‰ä¼šè°ƒç”¨å»¶ç»­å‡½æ•°ã€‚ 如果没有å‘生过任何让出,调用的函数正常返回, 那么 lua_pcallk ï¼ˆä»¥åŠ lua_callk)也会正常返回。 (当然,这个例å­ä¸­ä½ ä¹Ÿå¯ä»¥ä¸åœ¨ä¹‹åŽè°ƒç”¨å»¶ç»­å‡½æ•°ï¼Œ 而是在原函数的调用åŽç›´æŽ¥å†™ä¸Šéœ€è¦åšçš„工作。)

除了 Lua 状æ€ï¼Œå»¶ç»­å‡½æ•°è¿˜æœ‰ä¸¤ä¸ªå‚数: 一个是调用最åŽçš„状æ€ç ï¼Œå¦ä¸€ä¸ªä¸€å¼€å§‹ç”± lua_pcallk 传入的上下文 (ctx)。 (Lua 本身ä¸ä½¿ç”¨è¿™ä¸ªå€¼ï¼›å®ƒä»…仅从原函数转å‘这个值给延续函数。) 对于 lua_pcallk 而言, 状æ€ç å’Œ lua_pcallk 本应返回值相åŒï¼ŒåŒºåˆ«ä»…在于å‘ç”Ÿè¿‡è®©å‡ºåŽæ‰æ‰§è¡Œå®Œæ—¶ï¼Œçжæ€ç ä¸º LUA_YIELDï¼ˆè€Œä¸æ˜¯ LUA_OK)。 对于 lua_yieldk å’Œ lua_callk 而言, 调用延续函数传入的状æ€ç ä¸€å®šæ˜¯ LUA_YIELD。 (对这两个函数,Lua ä¸ä¼šå› ä»»ä½•错误而调用延续函数。 因为它们并ä¸å¤„ç†é”™è¯¯ã€‚) åŒæ ·ï¼Œå½“你使用 lua_callk 时, 你应该用 LUA_OK 作为状æ€ç æ¥è°ƒç”¨å»¶ç»­å‡½æ•°ã€‚ (对于 lua_yieldk, 几乎没有什么地方需è¦ç›´æŽ¥è°ƒç”¨å»¶ç»­å‡½æ•°ï¼Œ 因为 lua_yieldk 本身并ä¸ä¼šè¿”回。)

Lua 会把延续函数看作原函数。 延续函数将接收到和原函数相åŒçš„ Lua 栈,其接收到的 lua 状æ€ä¹Ÿå’Œ 被调函数若返回åŽåº”该有的状æ€ä¸€è‡´ã€‚ (例如, lua_callk 调用之åŽï¼Œ 栈中之å‰åŽ‹å…¥çš„å‡½æ•°å’Œè°ƒç”¨å‚æ•°éƒ½è¢«è°ƒç”¨äº§ç”Ÿçš„返回值所替代。) 这时也有相åŒçš„上值。 等到它返回的时候,Lua 会将其看待æˆåŽŸå‡½æ•°çš„è¿”å›žåŽ»æ“作。

4.8 – 函数和类型

è¿™é‡ŒæŒ‰å­—æ¯æ¬¡åºåˆ—出了所有 C API 中的函数和类型。 æ¯ä¸ªå‡½æ•°éƒ½æœ‰ä¸€ä¸ªè¿™æ ·çš„æç¤ºï¼š [-o, +p, x]

对于第一个域,o, 指的是该函数会从栈上弹出多少个元素。 第二个域,p, 指该函数会将多少个元素压栈。 ï¼ˆæ‰€æœ‰å‡½æ•°éƒ½ä¼šåœ¨å¼¹å‡ºå‚æ•°åŽå†æŠŠç»“果压栈。) x|y è¿™ç§å½¢å¼çš„域表示该函数根æ®å…·ä½“情况å¯èƒ½åŽ‹å…¥ï¼ˆæˆ–å¼¹å‡ºï¼‰ x 或 y 个元素; é—®å· '?' 表示 æˆ‘ä»¬æ— æ³•ä»…é€šè¿‡å‚æ•°æ¥äº†è§£è¯¥å‡½æ•°ä¼šå¼¹å‡º/压入多少元素 (比如,数é‡å–决于栈上有些什么)。 第三个域,x, 解释了该函数是å¦ä¼šæŠ›å‡ºé”™è¯¯ï¼š '-' 表示该函数ç»å¯¹ä¸ä¼šæŠ›å‡ºé”™è¯¯ï¼› 'e' 表示该函数å¯èƒ½æŠ›å‡ºé”™è¯¯ï¼› 'v' 表示该函数å¯èƒ½æŠ›å‡ºæœ‰æ„义的错误。


lua_absindex

[-0, +0, –]

int lua_absindex (lua_State *L, int idx);

å°†ä¸€ä¸ªå¯æŽ¥å—的索引 idx 转æ¢ä¸ºç»å¯¹ç´¢å¼• (å³ï¼Œä¸€ä¸ªä¸ä¾èµ–栈顶在哪的值)。


lua_Alloc

typedef void * (*lua_Alloc) (void *ud,
                             void *ptr,
                             size_t osize,
                             size_t nsize);

Lua çŠ¶æ€æœºä¸­ä½¿ç”¨çš„内存分é…器函数的类型。 内存分é…函数必须æä¾›ä¸€ä¸ªåŠŸèƒ½ç±»ä¼¼äºŽ realloc 但åˆä¸å®Œå…¨ç›¸åŒçš„函数。 å®ƒçš„å‚æ•°æœ‰ ud ,一个由 lua_newstate 传给它的指针; ptr ,一个指å‘已分é…出æ¥/å°†è¢«é‡æ–°åˆ†é…/è¦é‡Šæ”¾çš„å†…å­˜å—æŒ‡é’ˆï¼› osize ,内存å—原æ¥çš„尺寸或是关于什么将被分é…出æ¥çš„代ç ï¼› nsize ,新内存å—的尺寸。

如果 ptr 䏿˜¯ NULL, osize 是 ptr 指å‘的内存å—的尺寸, å³è¿™ä¸ªå†…å­˜å—当åˆè¢«åˆ†é…或é‡åˆ†é…的尺寸。

如果 ptr 是 NULL, osize 是 Lua å³å°†åˆ†é…对象类型的编ç ã€‚ 当(且仅当)Lua 创建一个对应类型的新对象时, osize 是 LUA_TSTRING,LUA_TTABLE,LUA_TFUNCTION, LUA_TUSERDATA,或 LUA_TTHREAD 中的一个。 è‹¥ osize 是其它类型,Lua 将为其它东西分é…内存。

Lua å‡å®šåˆ†é…器函数会éµå¾ªä»¥ä¸‹è¡Œä¸ºï¼š

当 nsize 是零时, 分é…器必须和 free 行为类似并返回 NULL。

当 nsize 䏿˜¯é›¶æ—¶ï¼Œ 分é…器必须和 realloc 行为类似。 如果分é…器无法完æˆè¯·æ±‚,返回 NULL。 Lua å‡å®šåœ¨ osize >= nsize æˆç«‹çš„æ¡ä»¶ä¸‹ï¼Œ 分é…器ç»ä¸ä¼šå¤±è´¥ã€‚

这里有一个简å•的分é…器函数的实现。 这个实现被放在补充库中,供 luaL_newstate 使用。

     static void *l_alloc (void *ud, void *ptr, size_t osize,
                                                size_t nsize) {
       (void)ud;  (void)osize;  /* not used */
       if (nsize == 0) {
         free(ptr);
         return NULL;
       }
       else
         return realloc(ptr, nsize);
     }

注æ„,标准 C èƒ½ç¡®ä¿ free(NULL) 没有副作用, 且 realloc(NULL,size) 等价于 malloc(size)。 这段代ç å‡å®š realloc 在缩å°å—长度时ä¸ä¼šå¤±è´¥ã€‚ (虽然标准 C 没有对此行为åšå‡ºä¿è¯ï¼Œä½†è¿™çœ‹èµ·æ¥æ˜¯ä¸€ä¸ªå®‰å…¨çš„å‡å®šã€‚)


lua_arith

[-(2|1), +1, e]

void lua_arith (lua_State *L, int op);

对栈顶的两个值(或者一个,比如å–å)åšä¸€æ¬¡æ•°å­¦æˆ–使“作。 其中,栈顶的那个值是第二个æ“作数。 它会弹出压入的值,并把结果放在栈顶。 这个函数éµå¾ª Lua 对应的æ“作符è¿ç®—规则 ï¼ˆå³æœ‰å¯èƒ½è§¦å‘元方法)。

op 的值必须是下列常é‡ä¸­çš„一个:


lua_atpanic

[-0, +0, –]

lua_CFunction lua_atpanic (lua_State *L, lua_CFunction panicf);

设置一个新的 panic 函数,并返回之å‰è®¾ç½®çš„那个。 (å‚è§ §4.6)。


lua_call

[-(nargs+1), +nresults, e]

void lua_call (lua_State *L, int nargs, int nresults);

调用一个函数。

è¦è°ƒç”¨ä¸€ä¸ªå‡½æ•°è¯·éµå¾ªä»¥ä¸‹å议: 首先,è¦è°ƒç”¨çš„函数应该被压入栈; 接ç€ï¼ŒæŠŠéœ€è¦ä¼ é€’ç»™è¿™ä¸ªå‡½æ•°çš„å‚æ•°æŒ‰æ­£åºåŽ‹æ ˆï¼› è¿™æ˜¯æŒ‡ç¬¬ä¸€ä¸ªå‚æ•°é¦–先压栈。 最åŽè°ƒç”¨ä¸€ä¸‹ lua_callï¼› nargs æ˜¯ä½ åŽ‹å…¥æ ˆçš„å‚æ•°ä¸ªæ•°ã€‚ 当函数调用完毕åŽï¼Œæ‰€æœ‰çš„傿•°ä»¥åŠå‡½æ•°æœ¬èº«éƒ½ä¼šå‡ºæ ˆã€‚ 而函数的返回值这时则被压栈。 返回值的个数将被调整为 nresults 个, é™¤éž nresults è¢«è®¾ç½®æˆ LUA_MULTRET。 åœ¨è¿™ç§æƒ…况下,所有的返回值都被压入堆栈中。 Lua 会ä¿è¯è¿”回值都放入栈空间中。 函数返回值将按正åºåŽ‹æ ˆï¼ˆç¬¬ä¸€ä¸ªè¿”å›žå€¼é¦–å…ˆåŽ‹æ ˆï¼‰ï¼Œ 因此在调用结æŸåŽï¼Œæœ€åŽä¸€ä¸ªè¿”回值将被放在栈顶。

被调用函数内å‘生的错误将(通过 longjmp )一直上抛。

下é¢çš„例å­ä¸­ï¼Œè¿™è¡Œ Lua 代ç ç­‰ä»·äºŽåœ¨å®¿ä¸»ç¨‹åºä¸­ç”¨ C 代ç åšä¸€äº›å·¥ä½œï¼š

     a = f("how", t.x, 14)

这里是 C 里的代ç ï¼š

     lua_getglobal(L, "f");                  /* function to be called */
     lua_pushliteral(L, "how");                       /* 1st argument */
     lua_getglobal(L, "t");                    /* table to be indexed */
     lua_getfield(L, -1, "x");        /* push result of t.x (2nd arg) */
     lua_remove(L, -2);                  /* remove 't' from the stack */
     lua_pushinteger(L, 14);                          /* 3rd argument */
     lua_call(L, 3, 1);     /* call 'f' with 3 arguments and 1 result */
     lua_setglobal(L, "a");                         /* set global 'a' */

注æ„上é¢è¿™æ®µä»£ç æ˜¯ 平衡 的: 到了最åŽï¼Œå †æ ˆæ¢å¤æˆåŽŸæœ‰çš„é…置。 这是一ç§è‰¯å¥½çš„编程习惯。


lua_callk

[-(nargs + 1), +nresults, e]

void lua_callk (lua_State *L,
                int nargs,
                int nresults,
                lua_KContext ctx,
                lua_KFunction k);

这个函数的行为和 lua_call 完全一致,åªä¸è¿‡å®ƒè¿˜å…许被调用的函数让出 (å‚è§ §4.7)。


lua_CFunction

typedef int (*lua_CFunction) (lua_State *L);

C 函数的类型。

为了正确的和 Lua 通讯, C 函数必须使用下列å议。 这个åè®®å®šä¹‰äº†å‚æ•°ä»¥åŠè¿”回值传递方法: C 函数通过 Lua ä¸­çš„æ ˆæ¥æŽ¥å—傿•°ï¼Œ 傿•°ä»¥æ­£åºå…¥æ ˆï¼ˆç¬¬ä¸€ä¸ªå‚数首先入栈)。 因此,当函数开始的时候, lua_gettop(L) å¯ä»¥è¿”å›žå‡½æ•°æ”¶åˆ°çš„å‚æ•°ä¸ªæ•°ã€‚ ç¬¬ä¸€ä¸ªå‚æ•°ï¼ˆå¦‚果有的è¯ï¼‰åœ¨ç´¢å¼• 1 的地方, 而最åŽä¸€ä¸ªå‚数在索引 lua_gettop(L) 处。 当需è¦å‘ Lua 返回值的时候, C 函数åªéœ€è¦æŠŠå®ƒä»¬ä»¥æ­£åºåŽ‹åˆ°å †æ ˆä¸Šï¼ˆç¬¬ä¸€ä¸ªè¿”å›žå€¼æœ€å…ˆåŽ‹å…¥ï¼‰ï¼Œ ç„¶åŽè¿”回这些返回值的个数。 在这些返回值之下的,堆栈上的东西都会被 Lua 丢掉。 å’Œ Lua 函数一样,从 Lua 中调用 C 函数也å¯ä»¥æœ‰å¾ˆå¤šè¿”回值。

下é¢è¿™ä¸ªä¾‹å­ä¸­çš„å‡½æ•°å°†æŽ¥æ”¶è‹¥å¹²æ•°å­—å‚æ•°ï¼Œå¹¶è¿”å›žå®ƒä»¬çš„å¹³å‡æ•°ä¸Žå’Œï¼š

     static int foo (lua_State *L) {
       int n = lua_gettop(L);    /* 傿•°çš„个数 */
       lua_Number sum = 0.0;
       int i;
       for (i = 1; i <= n; i++) {
         if (!lua_isnumber(L, i)) {
           lua_pushliteral(L, "incorrect argument");
           lua_error(L);
         }
         sum += lua_tonumber(L, i);
       }
       lua_pushnumber(L, sum/n);        /* 第一个返回值 */
       lua_pushnumber(L, sum);         /* 第二个返回值 */
       return 2;                   /* 返回值的个数 */
     }

lua_checkstack

[-0, +0, –]

int lua_checkstack (lua_State *L, int n);

ç¡®ä¿å †æ ˆä¸Šè‡³å°‘有 n 个é¢å¤–空ä½ã€‚ 如果ä¸èƒ½æŠŠå †æ ˆæ‰©å±•到相应的尺寸,函数返回å‡ã€‚ 失败的原因包括将把栈扩展到比固定最大尺寸还大 (至少是几åƒä¸ªå…ƒç´ ï¼‰æˆ–分é…内存失败。 这个函数永远ä¸ä¼šç¼©å°å †æ ˆï¼› å¦‚æžœå †æ ˆå·²ç»æ¯”需è¦çš„å¤§äº†ï¼Œé‚£ä¹ˆå°±ä¿æŒåŽŸæ ·ã€‚


lua_close

[-0, +0, –]

void lua_close (lua_State *L);

é”€æ¯æŒ‡å®š Lua çŠ¶æ€æœºä¸­çš„æ‰€æœ‰å¯¹è±¡ (如果有垃圾收集相关的元方法的è¯ï¼Œä¼šè°ƒç”¨å®ƒä»¬ï¼‰ï¼Œ å¹¶ä¸”é‡Šæ”¾çŠ¶æ€æœºä¸­ä½¿ç”¨çš„æ‰€æœ‰åЍæ€å†…存。 在一些平å°ä¸Šï¼Œä½ å¯ä»¥ä¸å¿…调用这个函数, 因为当宿主程åºç»“æŸçš„æ—¶å€™ï¼Œæ‰€æœ‰çš„资æºå°±è‡ªç„¶è¢«é‡Šæ”¾æŽ‰äº†ã€‚ å¦ä¸€æ–¹é¢ï¼Œé•¿æœŸè¿è¡Œçš„程åºï¼Œæ¯”如一个åŽå°ç¨‹åºæˆ–是一个网站æœåŠ¡å™¨ï¼Œ 会创建出多个 Lua çŠ¶æ€æœºã€‚那么就应该在ä¸éœ€è¦æ—¶èµ¶ç´§å…³é—­å®ƒä»¬ã€‚


lua_compare

[-0, +0, e]

int lua_compare (lua_State *L, int index1, int index2, int op);

比较两个 Lua 值。 当索引 index1 处的值通过 op 和索引 index2 å¤„çš„å€¼åšæ¯”è¾ƒåŽæ¡ä»¶æ»¡è¶³ï¼Œå‡½æ•°è¿”回 1 。 这个函数éµå¾ª Lua 对应的æ“ä½œè§„åˆ™ï¼ˆå³æœ‰å¯èƒ½è§¦å‘元方法)。 å之,函数返回 0。 当任何一个索引无效时,函数也会返回 0 。

op 值必须是下列常é‡ä¸­çš„一个:


lua_concat

[-n, +1, e]

void lua_concat (lua_State *L, int n);

连接栈顶的 n 个值, ç„¶åŽå°†è¿™äº›å€¼å‡ºæ ˆï¼Œå¹¶æŠŠç»“果放在栈顶。 如果 n 为 1 ,结果就是那个值放在栈上(å³ï¼Œå‡½æ•°ä»€ä¹ˆéƒ½ä¸åšï¼‰ï¼› 如果 n 为 0 ,结果是一个空串。 连接ä¾ç…§ Lua 中通常语义完æˆï¼ˆå‚è§ §3.4.6 )。


lua_copy

[-0, +0, –]

void lua_copy (lua_State *L, int fromidx, int toidx);

从索引 fromidx 处å¤åˆ¶ä¸€ä¸ªå€¼åˆ°ä¸€ä¸ªæœ‰æ•ˆç´¢å¼• toidx 处,覆盖那里的原有值。 ä¸ä¼šå½±å“其它ä½ç½®çš„值。


lua_createtable

[-0, +1, e]

void lua_createtable (lua_State *L, int narr, int nrec);

创建一张新的空表压栈。 傿•° narr 建议了这张表作为åºåˆ—使用时会有多少个元素; 傿•° nrec 建议了这张表å¯èƒ½æ‹¥æœ‰å¤šå°‘åºåˆ—之外的元素。 Lua 会使用这些建议æ¥é¢„分é…这张新表。 如果你知é“这张表用途的更多信æ¯ï¼Œé¢„分é…å¯ä»¥æé«˜æ€§èƒ½ã€‚ å¦åˆ™ï¼Œä½ å¯ä»¥ä½¿ç”¨å‡½æ•° lua_newtable 。


lua_dump

[-0, +0, e]

int lua_dump (lua_State *L,
                        lua_Writer writer,
                        void *data,
                        int strip);

把函数导出æˆäºŒè¿›åˆ¶ä»£ç å— 。 函数接收栈顶的 Lua 函数åšå‚数, ç„¶åŽç”Ÿæˆå®ƒçš„二进制代ç å—。 è‹¥è¢«å¯¼å‡ºçš„ä¸œè¥¿è¢«å†æ¬¡åŠ è½½ï¼Œ 加载的结果就相当于原æ¥çš„函数。 当它在产生代ç å—的时候, lua_dump 通过调用函数 writer (å‚è§ lua_Writer ) æ¥å†™å…¥æ•°æ®ï¼ŒåŽé¢çš„ data 傿•°ä¼šè¢«ä¼ å…¥ writer 。

如果 strip 为真, 二进制代ç å—å°†ä¸åŒ…å«è¯¥å‡½æ•°çš„调试信æ¯ã€‚

最åŽä¸€æ¬¡ç”± writer 的返回值将作为这个函数的返回值返回; 0 表示没有错误。

该函数ä¸ä¼šæŠŠ Lua 函数弹出堆栈。


lua_error

[-1, +0, v]

int lua_error (lua_State *L);

以栈顶的值作为错误对象,抛出一个 Lua 错误。 这个函数将åšä¸€æ¬¡é•¿è·³è½¬ï¼Œæ‰€ä»¥ä¸€å®šä¸ä¼šè¿”回 (å‚è§ luaL_error)。


lua_gc

[-0, +0, e]

int lua_gc (lua_State *L, int what, int data);

控制垃圾收集器。

这个函数根æ®å…¶å‚æ•° what å‘起几ç§ä¸åŒçš„任务:

关于这些选项的细节,å‚è§ collectgarbage 。


lua_getallocf

[-0, +0, –]

lua_Alloc lua_getallocf (lua_State *L, void **ud);

è¿”å›žç»™å®šçŠ¶æ€æœºçš„内存分é…器函数。 如果 ud 䏿˜¯ NULL , Lua 把设置内存分é…函数时设置的那个指针置入 *ud 。


lua_getfield

[-0, +1, e]

int lua_getfield (lua_State *L, int index, const char *k);

把 t[k] 的值压栈, 这里的 t 是索引指å‘的值。 在 Lua 中,这个函数å¯èƒ½è§¦å‘对应 "index" 事件对应的元方法 (å‚è§ §2.4 )。

函数将返回压入值的类型。


lua_getextraspace

[-0, +0, –]

void *lua_getextraspace (lua_State *L);

返回一个 Lua çŠ¶æ€æœºä¸­å…³è”çš„å†…å­˜å—æŒ‡é’ˆã€‚ 程åºå¯ä»¥æŠŠè¿™å—内存用于任何用途;而 Lua ä¸ä¼šä½¿ç”¨å®ƒã€‚

æ¯ä¸€ä¸ªæ–°çº¿ç¨‹éƒ½ä¼šæºå¸¦ä¸€å—内存, åˆå§‹åŒ–为主线程的这å—内存的副本。

默认é…置下,这å—内存的大å°ä¸ºç©ºæŒ‡é’ˆçš„大å°ã€‚ ä¸è¿‡ä½ å¯ä»¥é‡æ–°ç¼–译 Lua 设定这å—内存ä¸åŒçš„大å°ã€‚ (å‚è§ luaconf.h 中的 LUA_EXTRASPACE。)


lua_getglobal

[-0, +1, e]

int lua_getglobal (lua_State *L, const char *name);

把全局å˜é‡ name 里的值压栈,返回该值的类型。


lua_geti

[-0, +1, e]

int lua_geti (lua_State *L, int index, lua_Integer i);

把 t[i] 的值压栈, 这里的 t 指给定的索引指代的值。 和在 Lua 里一样,这个函数å¯èƒ½ä¼šè§¦å‘ "index" 事件的元方法 (å‚è§ §2.4)。

返回压入值的类型。


lua_getmetatable

[-0, +(0|1), –]

int lua_getmetatable (lua_State *L, int index);

如果该索引处的值有元表,则将其元表压栈,返回 1 。 å¦åˆ™ä¸ä¼šå°†ä»»ä½•东西入栈,返回 0 。


lua_gettable

[-1, +1, e]

int lua_gettable (lua_State *L, int index);

把 t[k] 的值压栈, 这里的 t 是指索引指å‘的值, 而 k 则是栈顶放的值。

这个函数会弹出堆栈上的键,把结果放在栈上相åŒä½ç½®ã€‚ 和在 Lua 中一样, 这个函数å¯èƒ½è§¦å‘对应 "index" 事件的元方法 (å‚è§ §2.4 )。

返回压入值的类型。


lua_gettop

[-0, +0, –]

int lua_gettop (lua_State *L);

返回栈顶元素的索引。 因为索引是从 1 开始编å·çš„, 所以这个结果等于栈上的元素个数; 特别指出,0 表示栈为空。


lua_getuservalue

[-0, +1, –]

int lua_getuservalue (lua_State *L, int index);

å°†ç»™å®šç´¢å¼•å¤„çš„ç”¨æˆ·æ•°æ®æ‰€å…³è”çš„ Lua 值压栈。

返回压入值的类型。


lua_insert

[-1, +1, –]

void lua_insert (lua_State *L, int index);

把栈顶元素移动到指定的有效索引处, 便¬¡ç§»åŠ¨è¿™ä¸ªç´¢å¼•ä¹‹ä¸Šçš„å…ƒç´ ã€‚ ä¸è¦ç”¨ä¼ªç´¢å¼•æ¥è°ƒç”¨è¿™ä¸ªå‡½æ•°ï¼Œ å› ä¸ºä¼ªç´¢å¼•æ²¡æœ‰çœŸæ­£æŒ‡å‘æ ˆä¸Šçš„ä½ç½®ã€‚


lua_Integer

typedef ... lua_Integer;

Lua 中的整数类型。

ç¼ºçœæ—¶ï¼Œè¿™ä¸ªå°±æ˜¯ long long, (通常是一个 64 ä½ä»¥äºŒä¸ºè¡¥ç çš„æ•´æ•°ï¼‰ï¼Œ 也å¯ä»¥ä¿®æ”¹å®ƒä¸º long 或 int (通常是一个 32 ä½ä»¥äºŒä¸ºè¡¥ç çš„æ•´æ•°ï¼‰ã€‚ (å‚è§ luaconf.h 中的 LUA_INT 。)

Lua 定义了两个常é‡ï¼š LUA_MININTEGER å’Œ LUA_MAXINTEGER æ¥è¡¨ç¤ºè¿™ä¸ªç±»åž‹å¯ä»¥è¡¨ç¤ºçš„æœ€å°å’Œæœ€å¤§å€¼ã€‚


lua_isboolean

[-0, +0, –]

int lua_isboolean (lua_State *L, int index);

å½“ç»™å®šç´¢å¼•çš„å€¼æ˜¯ä¸€ä¸ªå¸ƒå°”é‡æ—¶ï¼Œè¿”回 1 ,å¦åˆ™è¿”回 0 。


lua_iscfunction

[-0, +0, –]

int lua_iscfunction (lua_State *L, int index);

当给定索引的值是一个 C 函数时,返回 1 ,å¦åˆ™è¿”回 0 。


lua_isfunction

[-0, +0, –]

int lua_isfunction (lua_State *L, int index);

当给定索引的值是一个函数( C 或 Lua 函数å‡å¯ï¼‰æ—¶ï¼Œè¿”回 1 ,å¦åˆ™è¿”回 0 。


lua_isinteger

[-0, +0, –]

int lua_isinteger (lua_State *L, int index);

当给定索引的值是一个整数 (其值是一个数字,且内部以整数储存), 时,返回 1 ,å¦åˆ™è¿”回 0 。


lua_islightuserdata

[-0, +0, –]

int lua_islightuserdata (lua_State *L, int index);

当给定索引的值是一个轻é‡ç”¨æˆ·æ•°æ®æ—¶ï¼Œè¿”回 1 ,å¦åˆ™è¿”回 0 。


lua_isnil

[-0, +0, –]

int lua_isnil (lua_State *L, int index);

当给定索引的值是 nil 时,返回 1 ,å¦åˆ™è¿”回 0 。


lua_isnone

[-0, +0, –]

int lua_isnone (lua_State *L, int index);

当给定索引无效时,返回 1 ,å¦åˆ™è¿”回 0 。


lua_isnoneornil

[-0, +0, –]

int lua_isnoneornil (lua_State *L, int index);

当给定索引无效或其值是 nil 时, 返回 1 ,å¦åˆ™è¿”回 0 。


lua_isnumber

[-0, +0, –]

int lua_isnumber (lua_State *L, int index);

当给定索引的值是一个数字,或是一个å¯è½¬æ¢ä¸ºæ•°å­—的字符串时,返回 1 ,å¦åˆ™è¿”回 0 。


lua_isstring

[-0, +0, –]

int lua_isstring (lua_State *L, int index);

当给定索引的值是一个字符串或是一个数字 ï¼ˆæ•°å­—æ€»èƒ½è½¬æ¢æˆå­—符串)时,返回 1 ,å¦åˆ™è¿”回 0 。


lua_istable

[-0, +0, –]

int lua_istable (lua_State *L, int index);

当给定索引的值是一张表时,返回 1 ,å¦åˆ™è¿”回 0 。


lua_isthread

[-0, +0, –]

int lua_isthread (lua_State *L, int index);

当给定索引的值是一æ¡çº¿ç¨‹æ—¶ï¼Œè¿”回 1 ,å¦åˆ™è¿”回 0 。


lua_isuserdata

[-0, +0, –]

int lua_isuserdata (lua_State *L, int index);

当给定索引的值是一个用户数æ®ï¼ˆæ— è®ºæ˜¯å®Œå…¨çš„还是轻é‡çš„)时, 返回 1 ,å¦åˆ™è¿”回 0 。


lua_isyieldable

[-0, +0, –]

int lua_isyieldable (lua_State *L);

如果给定的å程å¯ä»¥è®©å‡ºï¼Œè¿”回 1 ,å¦åˆ™è¿”回 0 。


lua_KContext

typedef ... lua_KContext;

å»¶ç»­å‡½æ•°ä¸Šä¸‹æ–‡å‚æ•°çš„类型。 这一定是一个数字类型。 当有 intptr_t 时,被定义为 intptr_t , 因此它也å¯ä»¥ä¿å­˜æŒ‡é’ˆã€‚ å¦åˆ™ï¼Œå®ƒè¢«å®šä¹‰ä¸º ptrdiff_t。


lua_KFunction

typedef int (*lua_KFunction) (lua_State *L, int status, lua_KContext ctx);

延续函数的类型(å‚è§ §4.7 )。


lua_len

[-0, +1, e]

void lua_len (lua_State *L, int index);

返回给定索引的值的长度。 它等价于 Lua 中的 '#' æ“作符 (å‚è§ §3.4.7)。 它有å¯èƒ½è§¦å‘ "length" 事件对应的元方法 (å‚è§ §2.4 )。 结果压栈。


lua_load

[-0, +1, –]

int lua_load (lua_State *L,
              lua_Reader reader,
              void *data,
              const char *chunkname,
              const char *mode);

加载一段 Lua 代ç å—,但ä¸è¿è¡Œå®ƒã€‚ 如果没有错误, lua_load 把一个编译好的代ç å—作为一个 Lua 函数压到栈顶。 å¦åˆ™ï¼ŒåŽ‹å…¥é”™è¯¯æ¶ˆæ¯ã€‚

lua_load 的返回值å¯ä»¥æ˜¯ï¼š

lua_load 函数使用一个用户æä¾›çš„ reader 函数æ¥è¯»å–代ç å—(å‚è§ lua_Reader )。 data 傿•°ä¼šè¢«ä¼ å…¥ reader 函数。

chunkname è¿™ä¸ªå‚æ•°å¯ä»¥èµ‹äºˆä»£ç å—一个å字, 这个å字被用于出错信æ¯å’Œè°ƒè¯•ä¿¡æ¯ï¼ˆå‚è§ §4.9)。

lua_load 会自动检测代ç å—是文本的还是二进制的, ç„¶åŽåšå¯¹åº”的加载æ“作(å‚è§ç¨‹åº luac )。 字符串 mode 的作用和函数 load 一致。 它还å¯ä»¥æ˜¯ NULL 等价于字符串 "bt"。

lua_load 的内部会使用栈, å› æ­¤ reader å‡½æ•°å¿…é¡»æ°¸è¿œåœ¨æ¯æ¬¡è¿”回时ä¿ç•™æ ˆçš„原样。

如果返回的函数有上值, 第一个上值会被设置为 ä¿å­˜åœ¨æ³¨å†Œè¡¨ï¼ˆå‚è§ §4.5) LUA_RIDX_GLOBALS 索引处的全局环境。 在加载主代ç å—时,这个上值是 _ENV å˜é‡ï¼ˆå‚è§ §2.2)。 其它上值å‡è¢«åˆå§‹åŒ–为 nil。


lua_newstate

[-0, +0, –]

lua_State *lua_newstate (lua_Alloc f, void *ud);

创建一个è¿è¡Œåœ¨æ–°çš„ç‹¬ç«‹çš„çŠ¶æ€æœºä¸­çš„线程。 å¦‚æžœæ— æ³•åˆ›å»ºçº¿ç¨‹æˆ–çŠ¶æ€æœºï¼ˆç”±äºŽå†…存有é™ï¼‰åˆ™è¿”回 NULL。 傿•° f 是一个分é…器函数; Lua 将通过这个函数åšçŠ¶æ€æœºå†…æ‰€æœ‰çš„å†…å­˜åˆ†é…æ“作。 ç¬¬äºŒä¸ªå‚æ•° ud ï¼Œè¿™ä¸ªæŒ‡é’ˆå°†åœ¨æ¯æ¬¡è°ƒç”¨åˆ†é…器时被转入。


lua_newtable

[-0, +1, e]

void lua_newtable (lua_State *L);

创建一张空表,并将其压栈。 它等价于 lua_createtable(L, 0, 0) 。


lua_newthread

[-0, +1, e]

lua_State *lua_newthread (lua_State *L);

åˆ›å»ºä¸€æ¡æ–°çº¿ç¨‹ï¼Œå¹¶å°†å…¶åŽ‹æ ˆï¼Œ 并返回维护这个线程的 lua_State 指针。 这个函数返回的新线程共享原线程的全局环境, 但是它有独立的è¿è¡Œæ ˆã€‚

没有显å¼çš„函数å¯ä»¥ç”¨æ¥å…³é—­æˆ–é”€æ¯æŽ‰ä¸€ä¸ªçº¿ç¨‹ã€‚ 线程跟其它 Lua 对象一样是垃圾收集的æ¡ç›®ä¹‹ä¸€ã€‚


lua_newuserdata

[-0, +1, e]

void *lua_newuserdata (lua_State *L, size_t size);

这个函数分é…䏀嗿Œ‡å®šå¤§å°çš„内存å—, 把内存å—地å€ä½œä¸ºä¸€ä¸ªå®Œå…¨ç”¨æˆ·æ•°æ®åŽ‹æ ˆï¼Œ 并返回这个地å€ã€‚ 宿主程åºå¯ä»¥éšæ„使用这å—内存。


lua_next

[-1, +(2|0), e]

int lua_next (lua_State *L, int index);

从栈顶弹出一个键, ç„¶åŽæŠŠç´¢å¼•æŒ‡å®šçš„è¡¨ä¸­çš„ä¸€ä¸ªé”®å€¼å¯¹åŽ‹æ ˆ (弹出的键之åŽçš„ “下一†对)。 如果表中以无更多元素, 那么 lua_next 将返回 0 (什么也ä¸åŽ‹æ ˆï¼‰ã€‚

典型的é历方法是这样的:

     /*  表放在索引 't' 处 */
     lua_pushnil(L);  /* 第一个键 */
     while (lua_next(L, t) != 0) {
       /* 使用 '键' (在索引 -2 处) 和 '值' (在索引 -1 处)*/
       printf("%s - %s\n",
              lua_typename(L, lua_type(L, -2)),
              lua_typename(L, lua_type(L, -1)));
       /* 移除 '值' ï¼›ä¿ç•™ 'é”®' åšä¸‹ä¸€æ¬¡è¿­ä»£ */
       lua_pop(L, 1);
     }

在é历一张表的时候, ä¸è¦ç›´æŽ¥å¯¹é”®è°ƒç”¨ lua_tolstring , 除éžä½ çŸ¥é“这个键一定是一个字符串。 调用 lua_tolstring 有å¯èƒ½æ”¹å˜ç»™å®šç´¢å¼•ä½ç½®çš„值; 这会对下一次调用 lua_next 造æˆå½±å“。

关于迭代过程中修改被迭代的表的注æ„事项å‚è§ next 函数。


lua_Number

typedef double lua_Number;

Lua 中浮点数的类型。

Lua ä¸­æ•°å­—çš„ç±»åž‹ã€‚ç¼ºçœæ˜¯ double ,但是你å¯ä»¥æ”¹æˆ float 。 (å‚è§ luaconf.h 中的 LUA_REAL 。)


lua_numbertointeger

int lua_numbertointeger (lua_Number n, lua_Integer *p);

将一个 Lua 浮点数转æ¢ä¸ºä¸€ä¸ª Lua 整数。 这个å®å‡è®¾ n 有对应的整数值。 如果该值在 Lua æ•´æ•°å¯è¡¨ç¤ºèŒƒå›´å†…, 就将其转æ¢ä¸ºä¸€ä¸ªæ•´æ•°èµ‹ç»™ *p。 å®çš„结果是一个布尔é‡ï¼Œè¡¨ç¤ºè½¬æ¢æ˜¯å¦æˆåŠŸã€‚ (注æ„ã€ç”±äºŽåœ†æ•´å…³ç³»ï¼Œè¿™ä¸ªèŒƒå›´æµ‹è¯•ä¸ç”¨æ­¤å®å¾ˆéš¾åšå¯¹ã€‚)

è¯¥å®æœ‰å¯èƒ½å¯¹å…¶å‚æ•°åšå¤šæ¬¡å–值。


lua_pcall

[-(nargs + 1), +(nresults|1), –]

int lua_pcall (lua_State *L, int nargs, int nresults, int msgh);

ä»¥ä¿æŠ¤æ¨¡å¼è°ƒç”¨ä¸€ä¸ªå‡½æ•°ã€‚

nargs å’Œ nresults çš„å«ä¹‰ä¸Ž lua_call 中的相åŒã€‚ 如果在调用过程中没有å‘生错误, lua_pcall 的行为和 lua_call 完全一致。 但是,如果有错误å‘生的è¯ï¼Œ lua_pcall 会æ•获它, ç„¶åŽæŠŠå”¯ä¸€çš„å€¼ï¼ˆé”™è¯¯æ¶ˆæ¯ï¼‰åŽ‹æ ˆï¼Œç„¶åŽè¿”回错误ç ã€‚ åŒ lua_call 一样, lua_pcall æ€»æ˜¯æŠŠå‡½æ•°æœ¬èº«å’Œå®ƒçš„å‚æ•°ä»Žæ ˆä¸Šç§»é™¤ã€‚

如果 msgh 是 0 , 返回在栈顶的错误消æ¯å°±å’ŒåŽŸå§‹é”™è¯¯æ¶ˆæ¯å®Œå…¨ä¸€è‡´ã€‚ å¦åˆ™ï¼Œ msgh å°±è¢«å½“æˆæ˜¯ 错误处ç†å‡½æ•° 在栈上的索引ä½ç½®ã€‚ (在当å‰çš„实现里,这个索引ä¸èƒ½æ˜¯ä¼ªç´¢å¼•。) 在å‘生è¿è¡Œæ—¶é”™è¯¯æ—¶ï¼Œ è¿™ä¸ªå‡½æ•°ä¼šè¢«è°ƒç”¨è€Œå‚æ•°å°±æ˜¯é”™è¯¯æ¶ˆæ¯ã€‚ 错误处ç†å‡½æ•°çš„返回值将被 lua_pcall 作为错误消æ¯è¿”回在堆栈上。

典型的用法中,错误处ç†å‡½æ•°è¢«ç”¨æ¥ç»™é”™è¯¯æ¶ˆæ¯åŠ ä¸Šæ›´å¤šçš„è°ƒè¯•ä¿¡æ¯ï¼Œ 比如栈跟踪信æ¯ã€‚ 这些信æ¯åœ¨ lua_pcall 返回åŽï¼Œ 由于栈已ç»å±•开,所以收集ä¸åˆ°äº†ã€‚

lua_pcall 函数会返回下列常数 (定义在 lua.h 内)中的一个:


lua_pcallk

[-(nargs + 1), +(nresults|1), –]

int lua_pcallk (lua_State *L,
                int nargs,
                int nresults,
                int msgh,
                lua_KContext ctx,
                lua_KFunction k);

这个函数的行为和 lua_pcall 完全一致,åªä¸è¿‡å®ƒè¿˜å…许被调用的函数让出 (å‚è§ §4.7)。


lua_pop

[-n, +0, –]

void lua_pop (lua_State *L, int n);

从栈中弹出 n 个元素。


lua_pushboolean

[-0, +1, –]

void lua_pushboolean (lua_State *L, int b);

把 b 作为一个布尔é‡åŽ‹æ ˆã€‚


lua_pushcclosure

[-n, +1, e]

void lua_pushcclosure (lua_State *L, lua_CFunction fn, int n);

把一个新的 C 闭包压栈。

当创建了一个 C 函数åŽï¼Œ ä½ å¯ä»¥ç»™å®ƒå…³è”一些值, 这就是在创建一个 C 闭包(å‚è§ §4.4); æŽ¥ä¸‹æ¥æ— è®ºå‡½æ•°ä½•时被调用,这些值都å¯ä»¥è¢«è¿™ä¸ªå‡½æ•°è®¿é—®åˆ°ã€‚ 为了将一些值关è”到一个 C 函数上, 首先这些值需è¦å…ˆè¢«åŽ‹å…¥å †æ ˆï¼ˆå¦‚æžœæœ‰å¤šä¸ªå€¼ï¼Œç¬¬ä¸€ä¸ªå…ˆåŽ‹ï¼‰ã€‚ 接下æ¥è°ƒç”¨ lua_pushcclosure æ¥åˆ›å»ºå‡ºé—­åŒ…并把这个 C 函数压到栈上。 傿•° n 告之函数有多少个值需è¦å…³è”到函数上。 lua_pushcclosure 也会把这些值从栈上弹出。

n 的最大值是 255 。

当 n 为零时, 这个函数将创建出一个 è½»é‡ C 函数, å®ƒå°±æ˜¯ä¸€ä¸ªæŒ‡å‘ C 函数的指针。 è¿™ç§æƒ…况下,ä¸å¯èƒ½æŠ›å‡ºå†…存错误。


lua_pushcfunction

[-0, +1, –]

void lua_pushcfunction (lua_State *L, lua_CFunction f);

将一个 C 函数压栈。 这个函数接收一个 C 函数指针, 并将一个类型为 function çš„ Lua 值压栈。 当这个栈顶的值被调用时,将触å‘对应的 C 函数。

注册到 Lua 中的任何函数都必须éµå¾ªæ­£ç¡®çš„åè®®æ¥æŽ¥æ”¶å‚æ•°å’Œè¿”回值 (å‚è§ lua_CFunction )。

lua_pushcfunction 是作为一个å®å®šä¹‰å‡ºçŽ°çš„ï¼š

     #define lua_pushcfunction(L,f)  lua_pushcclosure(L,f,0)

lua_pushfstring

[-0, +1, e]

const char *lua_pushfstring (lua_State *L, const char *fmt, ...);

把一个格å¼åŒ–过的字符串压栈, ç„¶åŽè¿”回这个字符串的指针。 它和 C 函数 sprintf 比较åƒï¼Œ ä¸è¿‡æœ‰ä¸€äº›é‡è¦çš„区别:


lua_pushglobaltable

[-0, +1, –]

void lua_pushglobaltable (lua_State *L);

将全局环境压栈。


lua_pushinteger

[-0, +1, –]

void lua_pushinteger (lua_State *L, lua_Integer n);

把值为 n 的整数压栈。


lua_pushlightuserdata

[-0, +1, –]

void lua_pushlightuserdata (lua_State *L, void *p);

把一个轻é‡ç”¨æˆ·æ•°æ®åŽ‹æ ˆã€‚

ç”¨æˆ·æ•°æ®æ˜¯ä¿ç•™åœ¨ Lua 中的 C 值。 è½»é‡ç”¨æˆ·æ•°æ® 表示一个指针 void*。 å®ƒæ˜¯ä¸€ä¸ªåƒæ•°å­—一样的值: ä½ ä¸éœ€è¦ä¸“门创建它,它也没有独立的元表,而且也ä¸ä¼šè¢«æ”¶é›†ï¼ˆå› ä¸ºä»Žæ¥ä¸éœ€è¦åˆ›å»ºï¼‰ã€‚ åªè¦è¡¨ç¤ºçš„ C 地å€ç›¸åŒï¼Œä¸¤ä¸ªè½»é‡ç”¨æˆ·æ•°æ®å°±ç›¸ç­‰ã€‚


lua_pushliteral

[-0, +1, e]

const char *lua_pushliteral (lua_State *L, const char *s);

这个å®ç­‰ä»·äºŽ lua_pushstring, 区别仅在于åªèƒ½åœ¨ s 是一个字é¢é‡æ—¶æ‰èƒ½ç”¨å®ƒã€‚ 它会自动给出字符串的长度。


lua_pushlstring

[-0, +1, e]

const char *lua_pushlstring (lua_State *L, const char *s, size_t len);

把指针 s 指å‘的长度为 len 的字符串压栈。 Lua 对这个字符串åšä¸€ä¸ªå†…部副本(或是å¤ç”¨ä¸€ä¸ªå‰¯æœ¬ï¼‰ï¼Œ å› æ­¤ s 处的内存在函数返回åŽï¼Œå¯ä»¥é‡Šæ”¾æŽ‰æˆ–是立刻é‡ç”¨äºŽå…¶å®ƒç”¨é€”。 字符串内å¯ä»¥æ˜¯ä»»æ„二进制数æ®ï¼ŒåŒ…括零字符。

返回内部副本的指针。


lua_pushnil

[-0, +1, –]

void lua_pushnil (lua_State *L);

将空值压栈。


lua_pushnumber

[-0, +1, –]

void lua_pushnumber (lua_State *L, lua_Number n);

把一个值为 n 的浮点数压栈。


lua_pushstring

[-0, +1, e]

const char *lua_pushstring (lua_State *L, const char *s);

将指针 s 指å‘的零结尾的字符串压栈。Lua 对这个字符串åšä¸€ä¸ªå†…部副本(或是å¤ç”¨ä¸€ä¸ªå‰¯æœ¬ï¼‰ï¼Œ å› æ­¤ s 处的内存在函数返回åŽï¼Œå¯ä»¥é‡Šæ”¾æŽ‰æˆ–是立刻é‡ç”¨äºŽå…¶å®ƒç”¨é€”。

返回内部副本的指针。

如果 s 为 NULL,将 nil 压栈并返回 NULL。


lua_pushthread

[-0, +1, –]

int lua_pushthread (lua_State *L);

把 L 表示的线程压栈。 如果这个线程是当å‰çŠ¶æ€æœºçš„主线程的è¯ï¼Œè¿”回 1 。


lua_pushvalue

[-0, +1, –]

void lua_pushvalue (lua_State *L, int index);

把栈上给定索引处的元素作一个副本压栈。


lua_pushvfstring

[-0, +1, e]

const char *lua_pushvfstring (lua_State *L,
                              const char *fmt,
                              va_list argp);

等价于 lua_pushfstring , ä¸è¿‡æ˜¯ç”¨ va_list æŽ¥æ”¶å‚æ•°ï¼Œè€Œä¸æ˜¯ç”¨å¯å˜æ•°é‡çš„å®žé™…å‚æ•°ã€‚


lua_rawequal

[-0, +0, –]

int lua_rawequal (lua_State *L, int index1, int index2);

如果索引 index1 与索引 index2 处的值 本身相等(å³ä¸è°ƒç”¨å…ƒæ–¹æ³•),返回 1 。 å¦åˆ™è¿”回 0 。 当任何一个索引无效时,也返回 0 。


lua_rawget

[-1, +1, –]

int lua_rawget (lua_State *L, int index);

类似于 lua_gettable , 但是作一次直接访问(ä¸è§¦å‘元方法)。


lua_rawgeti

[-0, +1, –]

int lua_rawgeti (lua_State *L, int index, lua_Integer n);

把 t[n] 的值压栈, 这里的 t 是指给定索引处的表。 这是一次直接访问;就是说,它ä¸ä¼šè§¦å‘元方法。

返回入栈值的类型。


lua_rawgetp

[-0, +1, –]

int lua_rawgetp (lua_State *L, int index, const void *p);

把 t[k] 的值压栈, 这里的 t 是指给定索引处的表, k 是指针 p 对应的轻é‡ç”¨æˆ·æ•°æ®ã€‚ 这是一次直接访问;就是说,它ä¸ä¼šè§¦å‘元方法。

返回入栈值的类型。


lua_rawlen

[-0, +0, –]

size_t lua_rawlen (lua_State *L, int index);

返回给定索引处值的固有“长度â€ï¼š 对于字符串,它指字符串的长度; 对于表;它指ä¸è§¦å‘元方法的情况下å–长度æ“作('#')应得到的值; 对于用户数æ®ï¼Œå®ƒæŒ‡ä¸ºè¯¥ç”¨æˆ·æ•°æ®åˆ†é…的内存å—的大å°ï¼› 对于其它值,它为 0 。


lua_rawset

[-2, +0, e]

void lua_rawset (lua_State *L, int index);

类似于 lua_settable , 但是是åšä¸€æ¬¡ç›´æŽ¥èµ‹å€¼ï¼ˆä¸è§¦å‘元方法)。


lua_rawseti

[-1, +0, e]

void lua_rawseti (lua_State *L, int index, lua_Integer i);

等价于 t[i] = v , 这里的 t 是指给定索引处的表, 而 v 是栈顶的值。

这个函数会将值弹出栈。 赋值是直接的;å³ä¸ä¼šè§¦å‘元方法。


lua_rawsetp

[-1, +0, e]

void lua_rawsetp (lua_State *L, int index, const void *p);

等价于 t[k] = v , 这里的 t 是指给定索引处的表, k 是指针 p 对应的轻é‡ç”¨æˆ·æ•°æ®ã€‚ 而 v 是栈顶的值。

这个函数会将值弹出栈。 赋值是直接的;å³ä¸ä¼šè§¦å‘元方法。


lua_Reader

typedef const char * (*lua_Reader) (lua_State *L,
                                    void *data,
                                    size_t *size);

lua_load 用到的读å–器函数, æ¯æ¬¡å®ƒéœ€è¦ä¸€å—新的代ç å—的时候, lua_load 就调用读å–器, æ¯æ¬¡éƒ½ä¼šä¼ å…¥ä¸€ä¸ªå‚æ•° data 。 读å–器需è¦è¿”å›žå«æœ‰æ–°çš„代ç å—的一å—内存的指针, 并把 size 设为这å—内存的大å°ã€‚ 内存å—必须在下一次函数被调用之å‰ä¸€ç›´å­˜åœ¨ã€‚ 读å–器å¯ä»¥é€šè¿‡è¿”回 NULL 或设 size 为 0 æ¥æŒ‡ç¤ºä»£ç å—结æŸã€‚ 读å–器å¯èƒ½è¿”回多个å—,æ¯ä¸ªå—å¯ä»¥æœ‰ä»»æ„的大于零的尺寸。


lua_register

[-0, +0, e]

void lua_register (lua_State *L, const char *name, lua_CFunction f);

把 C 函数 f 设到全局å˜é‡ name 中。 它通过一个å®å®šä¹‰ï¼š

     #define lua_register(L,n,f) \
            (lua_pushcfunction(L, f), lua_setglobal(L, n))

lua_remove

[-1, +0, –]

void lua_remove (lua_State *L, int index);

从给定有效索引处移除一个元素, 把这个索引之上的所有元素移下æ¥å¡«è¡¥ä¸Šè¿™ä¸ªç©ºéš™ã€‚ ä¸èƒ½ç”¨ä¼ªç´¢å¼•æ¥è°ƒç”¨è¿™ä¸ªå‡½æ•°ï¼Œå› ä¸ºä¼ªç´¢å¼•并䏿Œ‡å‘真实的栈上的ä½ç½®ã€‚


lua_replace

[-1, +0, –]

void lua_replace (lua_State *L, int index);

把栈顶元素放置到给定ä½ç½®è€Œä¸ç§»åŠ¨å…¶å®ƒå…ƒç´  (因此覆盖了那个ä½ç½®å¤„的值),然åŽå°†æ ˆé¡¶å…ƒç´ å¼¹å‡ºã€‚


lua_resume

[-?, +?, –]

int lua_resume (lua_State *L, lua_State *from, int nargs);

在给定线程中å¯åŠ¨æˆ–å»¶ç»­ä¸€æ¡å程 。

è¦å¯åŠ¨ä¸€ä¸ªå程的è¯ï¼Œ ä½ éœ€è¦æŠŠä¸»å‡½æ•°ä»¥åŠå®ƒéœ€è¦çš„傿•°åŽ‹å…¥çº¿ç¨‹æ ˆï¼› ç„¶åŽè°ƒç”¨ lua_resume , 把 nargs è®¾ä¸ºå‚æ•°çš„个数。 这次调用会在å程挂起时或是结æŸè¿è¡ŒåŽè¿”回。 当函数返回时,堆栈中会有传给 lua_yield 的所有值, 或是主函数的所有返回值。 当å程让出, lua_resume 返回 LUA_YIELD , è‹¥å程结æŸè¿è¡Œä¸”没有任何错误时,返回 0 。 如果有错则返回错误代ç ï¼ˆå‚è§ lua_pcall )。

在å‘生错误的情况下, 堆栈没有展开, 因此你å¯ä»¥ä½¿ç”¨è°ƒè¯• API æ¥å¤„ç†å®ƒã€‚ é”™è¯¯æ¶ˆæ¯æ”¾åœ¨æ ˆé¡¶ã€‚

è¦å»¶ç»­ä¸€ä¸ªå程, ä½ éœ€è¦æ¸…除上次 lua_yield é—留下的所有结果, 你把需è¦ä¼ ç»™ yield 作结果的值压栈, ç„¶åŽè°ƒç”¨ lua_resume 。

傿•° from 表示å程从哪个å程中æ¥å»¶ç»­ L 的。 如果ä¸å­˜åœ¨è¿™æ ·ä¸€ä¸ªåç¨‹ï¼Œè¿™ä¸ªå‚æ•°å¯ä»¥æ˜¯ NULL 。


lua_rotate

[-0, +0, –]

void lua_rotate (lua_State *L, int idx, int n);

把从 idx 开始到栈顶的元素轮转 n 个ä½ç½®ã€‚ 对于 n ä¸ºæ­£æ•°æ—¶ï¼Œè½®è½¬æ–¹å‘æ˜¯å‘栈顶的; 当 n ä¸ºè´Ÿæ•°æ—¶ï¼Œå‘æ ˆåº•æ–¹å‘轮转 -n 个ä½ç½®ã€‚ n çš„ç»å¯¹å€¼ä¸å¯ä»¥æ¯”å‚于轮转的切片长度大。


lua_setallocf

[-0, +0, –]

void lua_setallocf (lua_State *L, lua_Alloc f, void *ud);

æŠŠæŒ‡å®šçŠ¶æ€æœºçš„分é…å™¨å‡½æ•°æ¢æˆå¸¦ä¸Šç”¨æˆ·æ•°æ® ud çš„ f 。


lua_setfield

[-1, +0, e]

void lua_setfield (lua_State *L, int index, const char *k);

åšä¸€ä¸ªç­‰ä»·äºŽ t[k] = v çš„æ“作, 这里 t 是给出的索引处的值, 而 v 是栈顶的那个值。

这个函数将把这个值弹出栈。 跟在 Lua 中一样,这个函数å¯èƒ½è§¦å‘一个 "newindex" 事件的元方法 (å‚è§ §2.4)。


lua_setglobal

[-1, +0, e]

void lua_setglobal (lua_State *L, const char *name);

从堆栈上弹出一个值,并将其设为全局å˜é‡ name 的新值。


lua_seti

[-1, +0, e]

void lua_seti (lua_State *L, int index, lua_Integer n);

åšä¸€ä¸ªç­‰ä»·äºŽ t[n] = v çš„æ“作, 这里 t 是给出的索引处的值, 而 v 是栈顶的那个值。

这个函数将把这个值弹出栈。 跟在 Lua 中一样,这个函数å¯èƒ½è§¦å‘一个 "newindex" 事件的元方法 (å‚è§ §2.4)。


lua_setmetatable

[-1, +0, –]

void lua_setmetatable (lua_State *L, int index);

把一张表弹出栈,并将其设为给定索引处的值的元表。


lua_settable

[-2, +0, e]

void lua_settable (lua_State *L, int index);

åšä¸€ä¸ªç­‰ä»·äºŽ t[k] = v çš„æ“作, 这里 t 是给出的索引处的值, v 是栈顶的那个值, k 是栈顶之下的值。

这个函数会将键和值都弹出栈。 跟在 Lua 中一样,这个函数å¯èƒ½è§¦å‘一个 "newindex" 事件的元方法 (å‚è§ §2.4)。


lua_settop

[-?, +?, –]

void lua_settop (lua_State *L, int index);

傿•°å…è®¸ä¼ å…¥ä»»ä½•ç´¢å¼•ä»¥åŠ 0 。 它将把堆栈的栈顶设为这个索引。 如果新的栈顶比原æ¥çš„大, 超出部分的新元素将被填为 nil 。 如果 index 为 0 , 把栈上所有元素移除。


lua_setuservalue

[-1, +0, –]

void lua_setuservalue (lua_State *L, int index);

从栈上弹出一个值并将其设为给定索引处用户数æ®çš„å…³è”值。


lua_State

typedef struct lua_State lua_State;

一个ä¸é€æ˜Žçš„结构, 它指å‘一æ¡çº¿ç¨‹å¹¶é—´æŽ¥ï¼ˆé€šè¿‡è¯¥çº¿ç¨‹ï¼‰å¼•用了整个 Lua 解释器的状æ€ã€‚ Lua 库是完全å¯é‡å…¥çš„: 它没有任何全局å˜é‡ã€‚ çŠ¶æ€æœºæ‰€æœ‰çš„ä¿¡æ¯éƒ½å¯ä»¥é€šè¿‡è¿™ä¸ªç»“构访问到。

è¿™ä¸ªç»“æž„çš„æŒ‡é’ˆå¿…é¡»ä½œä¸ºç¬¬ä¸€ä¸ªå‚æ•°ä¼ é€’ç»™æ¯ä¸€ä¸ªåº“函数。 lua_newstate 是一个例外, 这个函数会从头创建一个 Lua çŠ¶æ€æœºã€‚


lua_status

[-0, +0, –]

int lua_status (lua_State *L);

返回线程 L 的状æ€ã€‚

æ­£å¸¸çš„çº¿ç¨‹çŠ¶æ€æ˜¯ 0 (LUA_OK)。 当线程用 lua_resume 执行完毕并抛出了一个错误时, 状æ€å€¼æ˜¯é”™è¯¯ç ã€‚ 如果线程被挂起,状æ€ä¸º LUA_YIELD 。

ä½ åªèƒ½åœ¨çжæ€ä¸º LUA_OK 的线程中调用函数。 ä½ å¯ä»¥å»¶ç»­ä¸€ä¸ªçжæ€ä¸º LUA_OK 的线程 (用于开始新å程)或是状æ€ä¸º LUA_YIELD 的线程 (用于延续å程)。


lua_stringtonumber

[-0, +1, –]

size_t lua_stringtonumber (lua_State *L, const char *s);

将一个零结尾的字符串 s 转æ¢ä¸ºä¸€ä¸ªæ•°å­—, 将这个数字压栈,并返回字符串的总长度(å³é•¿åº¦åŠ ä¸€ï¼‰ã€‚ 转æ¢çš„结果å¯èƒ½æ˜¯æ•´æ•°ä¹Ÿå¯èƒ½æ˜¯æµ®ç‚¹æ•°ï¼Œ è¿™å–决于 Lua 的转æ¢è¯­æ³•(å‚è§ §3.1)。 这个字符串å¯ä»¥æœ‰å‰ç½®å’ŒåŽç½®çš„空格以åŠç¬¦å·ã€‚ 如果字符串并éžä¸€ä¸ªæœ‰æ•ˆçš„æ•°å­—,返回 0 å¹¶ä¸æŠŠä»»ä½•ä¸œè¥¿åŽ‹æ ˆã€‚ (注æ„,这个结果å¯ä»¥å½“æˆä¸€ä¸ªå¸ƒå°”é‡ä½¿ç”¨ï¼Œä¸ºçœŸå³è½¬æ¢æˆåŠŸã€‚ï¼‰


lua_toboolean

[-0, +0, –]

int lua_toboolean (lua_State *L, int index);

把给定索引处的 Lua 值转æ¢ä¸ºä¸€ä¸ª C 中的布尔é‡ï¼ˆ 0 或是 1 )。 å’Œ Lua 中åšçš„æ‰€æœ‰æµ‹è¯•一样, lua_toboolean 会把任何ä¸åŒäºŽ false å’Œ nil 的值当作真返回; å¦åˆ™å°±è¿”回å‡ã€‚ ï¼ˆå¦‚æžœä½ æƒ³åªæŽ¥æ”¶çœŸæ­£çš„ boolean 值, 就需è¦ä½¿ç”¨ lua_isboolean æ¥æµ‹è¯•值的类型。)


lua_tocfunction

[-0, +0, –]

lua_CFunction lua_tocfunction (lua_State *L, int index);

把给定索引处的 Lua 值转æ¢ä¸ºä¸€ä¸ª C 函数。 这个值必须是一个 C 函数; å¦‚æžœä¸æ˜¯å°±è¿”回 NULL 。


lua_tointeger

[-0, +0, –]

lua_Integer lua_tointeger (lua_State *L, int index);

等价于调用 lua_tointegerx, 其傿•° isnum 为 NULL。


lua_tointegerx

[-0, +0, –]

lua_Integer lua_tointegerx (lua_State *L, int index, int *isnum);

将给定索引处的 Lua 值转æ¢ä¸ºå¸¦ç¬¦å·çš„æ•´æ•°ç±»åž‹ lua_Integer。 这个 Lua 值必须是一个整数,或是一个å¯ä»¥è¢«è½¬æ¢ä¸ºæ•´æ•° (å‚è§ §3.4.3)的数字或字符串; å¦åˆ™ï¼Œlua_tointegerx 返回 0 。

如果 isnum 䏿˜¯ NULL, *isnum 会被设为æ“ä½œæ˜¯å¦æˆåŠŸã€‚


lua_tolstring

[-0, +0, e]

const char *lua_tolstring (lua_State *L, int index, size_t *len);

把给定索引处的 Lua 值转æ¢ä¸ºä¸€ä¸ª C 字符串。 如果 len ä¸ä¸º NULL , 它还把字符串长度设到 *len 中。 这个 Lua 值必须是一个字符串或是一个数字; å¦åˆ™è¿”回 NULL 。 如果值是一个数字, lua_tolstring 还会 把堆栈中的那个值的实际类型转æ¢ä¸ºä¸€ä¸ªå­—符串。 (当é历一张表的时候, 若把 lua_tolstring 作用在键上, è¿™ä¸ªè½¬æ¢æœ‰å¯èƒ½å¯¼è‡´ lua_next 弄错。)

lua_tolstring è¿”å›žä¸€ä¸ªå·²å¯¹é½æŒ‡é’ˆ æŒ‡å‘ Lua çŠ¶æ€æœºä¸­çš„字符串。 这个字符串总能ä¿è¯ ( C è¦æ±‚的)最åŽä¸€ä¸ªå­—符为零 ('\0') , 而且它å…许在字符串内包å«å¤šä¸ªè¿™æ ·çš„零。

因为 Lua 中å¯èƒ½å‘生垃圾收集, 所以ä¸ä¿è¯ lua_tolstring 返回的指针, 在对应的值从堆栈中移除åŽä¾ç„¶æœ‰æ•ˆã€‚


lua_tonumber

[-0, +0, –]

lua_Number lua_tonumber (lua_State *L, int index);

等价于调用 lua_tonumberx, 其傿•° isnum 为 NULL。


lua_tonumberx

[-0, +0, –]

lua_Number lua_tonumberx (lua_State *L, int index, int *isnum);

把给定索引处的 Lua 值转æ¢ä¸º lua_Number 这样一个 C 类型 (å‚è§ lua_Number )。 这个 Lua 值必须是一个数字或是一个å¯è½¬æ¢ä¸ºæ•°å­—的字符串 (å‚è§ §3.4.3); å¦åˆ™ï¼Œ lua_tonumberx 返回 0 。

如果 isnum 䏿˜¯ NULL, *isnum 会被设为æ“ä½œæ˜¯å¦æˆåŠŸã€‚


lua_topointer

[-0, +0, –]

const void *lua_topointer (lua_State *L, int index);

把给定索引处的值转æ¢ä¸ºä¸€èˆ¬çš„ C 指针 (void*) 。 这个值å¯ä»¥æ˜¯ä¸€ä¸ªç”¨æˆ·å¯¹è±¡ï¼Œè¡¨ ,线程或是一个函数; å¦åˆ™ï¼Œ lua_topointer 返回 NULL 。 ä¸åŒçš„对象有ä¸åŒçš„æŒ‡é’ˆã€‚ ä¸å­˜åœ¨æŠŠæŒ‡é’ˆå†è½¬å›žåŽŸæœ‰ç±»åž‹çš„æ–¹æ³•ã€‚

这个函数通常åªç”¨äºŽè°ƒè¯•ä¿¡æ¯ã€‚


lua_tostring

[-0, +0, e]

const char *lua_tostring (lua_State *L, int index);

等价于调用 lua_tolstring , 其傿•° len 为 NULL 。


lua_tothread

[-0, +0, –]

lua_State *lua_tothread (lua_State *L, int index);

把给定索引处的值转æ¢ä¸ºä¸€ä¸ª Lua 线程 (表示为 lua_State*)。 这个值必须是一个线程; å¦åˆ™å‡½æ•°è¿”回 NULL。


lua_touserdata

[-0, +0, –]

void *lua_touserdata (lua_State *L, int index);

如果给定索引处的值是一个完全用户数æ®ï¼Œ 函数返回其内存å—的地å€ã€‚ 如果值是一个轻é‡ç”¨æˆ·æ•°æ®ï¼Œ 那么就返回它表示的指针。 å¦åˆ™ï¼Œè¿”回 NULL 。


lua_type

[-0, +0, –]

int lua_type (lua_State *L, int index);

返回给定有效索引处值的类型, 当索引无效(或无法访问)时则返回 LUA_TNONE。 lua_type 返回的类型被编ç ä¸ºä¸€äº›ä¸ªåœ¨ lua.h 中定义的常é‡ï¼š LUA_TNIL, LUA_TNUMBER, LUA_TBOOLEAN, LUA_TSTRING, LUA_TTABLE, LUA_TFUNCTION, LUA_TUSERDATA, LUA_TTHREAD, LUA_TLIGHTUSERDATA。


lua_typename

[-0, +0, –]

const char *lua_typename (lua_State *L, int tp);

返回 tp 表示的类型å, 这个 tp 必须是 lua_type å¯èƒ½è¿”回的值中之一。


lua_Unsigned

typedef ... lua_Unsigned;

lua_Integer 的无符å·ç‰ˆæœ¬ã€‚


lua_upvalueindex

[-0, +0, –]

int lua_upvalueindex (int i);

返回当å‰è¿è¡Œçš„函数(å‚è§ §4.4)的第 i 个上值的伪索引。


lua_version

[-0, +0, v]

const lua_Number *lua_version (lua_State *L);

返回ä¿å­˜åœ¨ Lua 内核中储存的版本数字的地å€ã€‚ å½“è°ƒç”¨æ—¶ä¼ å…¥ä¸€ä¸ªåˆæ³•çš„ lua_State , è¿”å›žåˆ›å»ºè¯¥çŠ¶æ€æœºæ—¶çš„版本地å€ã€‚ 如果用 NULL 调用, 返回调用者的版本地å€ã€‚


lua_Writer

typedef int (*lua_Writer) (lua_State *L,
                           const void* p,
                           size_t sz,
                           void* ud);

被 lua_dump 用到的写入器函数。 æ¯æ¬¡ lua_dump 产生了一段新的代ç å—, 它都会调用写入器。 ä¼ å…¥è¦å†™å…¥çš„缓冲区 (p) 和它的尺寸 (sz) , 以åŠä¼ ç»™ lua_dump çš„å‚æ•° data 。

写入器会返回一个错误ç ï¼š 0 表示没有错误; 别的值å‡è¡¨ç¤ºä¸€ä¸ªé”™è¯¯ï¼Œ 并且会让 lua_dump åœæ­¢å†æ¬¡è°ƒç”¨å†™å…¥å™¨ã€‚


lua_xmove

[-?, +?, –]

void lua_xmove (lua_State *from, lua_State *to, int n);

交æ¢åŒä¸€ä¸ªçŠ¶æ€æœºä¸‹ä¸åŒçº¿ç¨‹ä¸­çš„值。

这个函数会从 from 的栈上弹出 n 个值, ç„¶åŽæŠŠå®ƒä»¬åŽ‹å…¥ to 的栈上。


lua_yield

[-?, +?, e]

int lua_yield (lua_State *L, int nresults);

这个函数等价于调用 lua_yieldk, ä¸åŒçš„æ˜¯ä¸æä¾›å»¶ç»­å‡½æ•°ï¼ˆå‚è§ §4.7)。 因此,当线程被延续,线程会继续è¿è¡Œè°ƒç”¨ lua_yield 函数的函数。


lua_yieldk

[-?, +?, e]

int lua_yieldk (lua_State *L,
                int nresults,
                lua_KContext ctx,
                lua_KFunction k);

让出å程(线程)。

当 C 函数调用了 lua_yieldk, 当å‰è¿è¡Œçš„å程会挂起, å¯åŠ¨è¿™ä¸ªçº¿ç¨‹çš„ lua_resume 调用返回。 傿•° nresults 指栈上需返回给 lua_resume 的返回值的个数。

当åç¨‹å†æ¬¡è¢«å»¶ç»­æ—¶ï¼Œ Lua 调用延续函数 k ç»§ç»­è¿è¡Œè¢«æŒ‚起(å‚è§ §4.7)的 C 函数。 延续函数会从å‰ä¸€ä¸ªå‡½æ•°ä¸­æŽ¥æ”¶åˆ°ç›¸åŒçš„æ ˆï¼Œ 栈中的 n 个返回值被移除而压入了从 lua_resume ä¼ å…¥çš„å‚æ•°ã€‚ 此外,延续函数还会收到传给 lua_yieldk çš„å‚æ•° ctx。

通常,这个函数ä¸ä¼šè¿”回; 当å程一次次延续,将从延续函数继续è¿è¡Œã€‚ 然而,有一个例外: 当这个函数从一个é€è¡Œè¿è¡Œçš„é’©å­å‡½æ•°ï¼ˆå‚è§ §4.9) 中调用时,lua_yieldk ä¸å¯ä»¥æä¾›å»¶ç»­å‡½æ•°ã€‚ (也就是类似 lua_yield 的形å¼ï¼‰ï¼Œ 而此时,钩å­å‡½æ•°åœ¨è°ƒç”¨å®Œè®©å‡ºåŽå°†ç«‹åˆ»è¿”回。 Lua 会使å程让出,一旦åç¨‹å†æ¬¡è¢«å»¶ç»­ï¼Œ 触å‘é’©å­çš„函数会继续正常è¿è¡Œã€‚

当一个线程处于未æä¾›å»¶ç»­å‡½æ•°çš„ C 调用中,调用它会抛出一个错误。 从并éžç”¨å»¶ç»­æ–¹å¼ï¼ˆä¾‹å¦‚:主线程)å¯åŠ¨çš„çº¿ç¨‹ä¸­è°ƒç”¨å®ƒä¹Ÿä¼šè¿™æ ·ã€‚

4.9 – 调试接å£

Lua 没有内置的调试机制。 但是它æä¾›äº†ä¸€ç»„特殊的函数接å£ä»¥åŠ é’©å­ã€‚ 这组接å£å¯ç”¨äºŽæž„建出ä¸åŒçš„è°ƒè¯•å™¨ã€æ€§èƒ½å‰–æžå™¨ã€ 或是其它需è¦ä»Žè§£é‡Šå™¨èŽ·å–“内部信æ¯â€çš„工具。


lua_Debug

typedef struct lua_Debug {
  int event;
  const char *name;           /* (n) */
  const char *namewhat;       /* (n) */
  const char *what;           /* (S) */
  const char *source;         /* (S) */
  int currentline;            /* (l) */
  int linedefined;            /* (S) */
  int lastlinedefined;        /* (S) */
  unsigned char nups;         /* (u) ä¸Šå€¼çš„æ•°é‡ */
  unsigned char nparams;      /* (u) 傿•°çš„æ•°é‡ */
  char isvararg;              /* (u) */
  char istailcall;            /* (t) */
  char short_src[LUA_IDSIZE]; /* (S) */
  /* ç§æœ‰éƒ¨åˆ† */
  其它域
} lua_Debug;

这是一个æºå¸¦æœ‰æœ‰å…³å‡½æ•°æˆ–活动记录的å„ç§ä¿¡æ¯çš„结构。 lua_getstack åªä¼šå¡«å……ç»“æž„çš„ç§æœ‰éƒ¨åˆ†ä¾›åŽé¢ä½¿ç”¨ã€‚ 调用 lua_getinfo å¯ä»¥åœ¨ lua_Debug 中填充那些å¯è¢«ä½¿ç”¨çš„ä¿¡æ¯åŸŸã€‚

下é¢å¯¹ lua_Debug çš„å„个域åšä¸€ä¸ªè¯´æ˜Žï¼š


lua_gethook

[-0, +0, –]

lua_Hook lua_gethook (lua_State *L);

返回当å‰çš„é’©å­å‡½æ•°ã€‚


lua_gethookcount

[-0, +0, –]

int lua_gethookcount (lua_State *L);

返回当å‰çš„é’©å­è®¡æ•°ã€‚


lua_gethookmask

[-0, +0, –]

int lua_gethookmask (lua_State *L);

返回当å‰çš„钩孿ީç ã€‚


lua_getinfo

[-(0|1), +(0|1|2), e]

int lua_getinfo (lua_State *L, const char *what, lua_Debug *ar);

返回一个指定的函数或函数调用的信æ¯ã€‚

当用于å–å¾—ä¸€æ¬¡å‡½æ•°è°ƒç”¨çš„ä¿¡æ¯æ—¶ï¼Œ 傿•° ar 必须是一个有效的活动的记录。 è¿™æ¡è®°å½•å¯ä»¥æ˜¯å‰ä¸€æ¬¡è°ƒç”¨ lua_getstack 得到的, æˆ–æ˜¯ä¸€ä¸ªé’©å­ ï¼ˆå‚è§ lua_Hook ï¼‰å¾—åˆ°çš„å‚æ•°ã€‚

用于获å–ä¸€ä¸ªå‡½æ•°çš„ä¿¡æ¯æ—¶ï¼Œ å¯ä»¥æŠŠè¿™ä¸ªå‡½æ•°åŽ‹å…¥å †æ ˆï¼Œ ç„¶åŽæŠŠ what 字符串以字符 '>' 起头。 (这会让 lua_getinfo 从栈顶上弹出函数。) 例如,想知é“函数 f 是在哪一行定义的, ä½ å¯ä»¥ä½¿ç”¨ä¸‹åˆ—代ç ï¼š

     lua_Debug ar;
     lua_getglobal(L, "f");  /* å–得全局å˜é‡ 'f' */
     lua_getinfo(L, ">S", &ar);
     printf("%d\n", ar.linedefined);

what 字符串中的æ¯ä¸ªå­—符都筛选出结构 ar 结构中一些域用于填充, 或是把一个值压入堆栈:

这个函数出错会返回 0 (例如,what 中有一个无效选项)。


lua_getlocal

[-0, +(0|1), –]

const char *lua_getlocal (lua_State *L, const lua_Debug *ar, int n);

从给定活动记录或从一个函数中获å–一个局部å˜é‡çš„ä¿¡æ¯ã€‚

å¯¹äºŽç¬¬ä¸€ç§æƒ…况, 傿•° ar 必须是一个有效的活动的记录。 è¿™æ¡è®°å½•å¯ä»¥æ˜¯å‰ä¸€æ¬¡è°ƒç”¨ lua_getstack 得到的, æˆ–æ˜¯ä¸€ä¸ªé’©å­ ï¼ˆå‚è§ lua_Hook ï¼‰çš„å‚æ•°ã€‚ 索引 n ç”¨äºŽé€‰æ‹©è¦æ£€é˜…哪个局部å˜é‡ï¼› å‚è§ debug.getlocal 中关于å˜é‡çš„索引和å字的介ç»ã€‚

lua_getlocal å°†å˜é‡çš„值压栈,并返回其å字。

å¯¹äºŽç¬¬äºŒç§æƒ…况,ar 必须填 NULL 。 éœ€è¦æŽ¢çŸ¥çš„å‡½æ•°å¿…é¡»æ”¾åœ¨æ ˆé¡¶ã€‚ å¯¹äºŽè¿™ç§æƒ…å†µï¼Œåªæœ‰ Lua å‡½æ•°çš„å½¢å‚æ˜¯å¯è§çš„ (没有关于还有哪些活动å˜é‡çš„ä¿¡æ¯ï¼‰ 也ä¸ä¼šæœ‰ä»»ä½•值压栈。

当索引大于活动的局部å˜é‡çš„æ•°é‡ï¼Œ 返回 NULL (无任何压栈)


lua_getstack

[-0, +0, –]

int lua_getstack (lua_State *L, int level, lua_Debug *ar);

获å–解释器的è¿è¡Œæ—¶æ ˆçš„ä¿¡æ¯ã€‚

这个函数用正在è¿è¡Œä¸­çš„æŒ‡å®šå±‚次处函数的 活动记录 æ¥å¡«å†™ lua_Debug 结构的一部分。 0 层表示当å‰è¿è¡Œçš„函数, n+1 层的函数就是调用第 n 层 (尾调用例外,它ä¸ç®—在栈层次中) 函数的那一个。 如果没有错误, lua_getstack 返回 1 ï¼› 当调用传入的层次大于堆栈深度的时候,返回 0 。


lua_getupvalue

[-0, +(0|1), –]

const char *lua_getupvalue (lua_State *L, int funcindex, int n);

获å–一个闭包的上值信æ¯ã€‚ (对于 Lua 函数,上值是函数需è¦ä½¿ç”¨çš„外部局部å˜é‡ï¼Œ 因此这些å˜é‡è¢«åŒ…å«åœ¨é—­åŒ…中。) lua_getupvalue 获å–第 n 个上值, 把这个上值的值压栈, 并且返回它的å字。 funcindex 指å‘闭包在栈上的ä½ç½®ã€‚ ( 因为上值在整个函数中都有效,所以它们没有特别的次åºã€‚ å› æ­¤ï¼Œå®ƒä»¬ä»¥å­—æ¯æ¬¡åºæ¥ç¼–å·ã€‚)

å½“ç´¢å¼•å·æ¯”上值数é‡å¤§çš„æ—¶å€™ï¼Œ 返回 NULL(而且ä¸ä¼šåŽ‹å…¥ä»»ä½•ä¸œè¥¿ï¼‰ã€‚ 对于 C 函数,所有上值的å字都是空串 ""。


lua_Hook

typedef void (*lua_Hook) (lua_State *L, lua_Debug *ar);

用于调试的钩å­å‡½æ•°ç±»åž‹ã€‚

无论何时钩å­è¢«è°ƒç”¨ï¼Œå®ƒçš„傿•° ar 中的 event 域都被设为触å‘é’©å­çš„事件。 Lua 把这些事件定义为以下常é‡ï¼š LUA_HOOKCALL,LUA_HOOKRET, LUA_HOOKTAILCALL,LUA_HOOKLINE, LUA_HOOKCOUNT。 除此之外,对于 line 事件, currentline 域也被设置。 è¦æƒ³èŽ·å¾— ar 中的其他域, é’©å­å¿…须调用 lua_getinfo 。

对于 call 事件,event å¯ä»¥æ˜¯ LUA_HOOKCALL 这个通常值, 或是 LUA_HOOKTAILCALL 表示尾调用; åŽä¸€ç§æƒ…况,没有对应的返回事件。

当 Lua è¿è¡Œåœ¨ä¸€ä¸ªé’©å­å†…部时, 它将å±è”½æŽ‰å…¶å®ƒå¯¹é’©å­çš„调用。 也就是说,如果一个钩å­å‡½æ•°å†…å†è°ƒå›ž Lua æ¥æ‰§è¡Œä¸€ä¸ªå‡½æ•°æˆ–是一个代ç å— , 这个执行æ“作ä¸ä¼šè§¦å‘任何的钩å­ã€‚

é’©å­å‡½æ•°ä¸èƒ½æœ‰å»¶ç»­ç‚¹ï¼Œ å³ä¸èƒ½ç”¨ä¸€ä¸ªéžç©ºçš„ k 调用 lua_yieldk, lua_pcallk,或 lua_callk。

é’©å­å‡½æ•°å¯ä»¥åœ¨æ»¡è¶³ä¸‹åˆ—æ¡ä»¶æ—¶è®©å‡ºï¼š åªæœ‰è¡Œè®¡æ•°äº‹ä»¶å¯ä»¥è®©å‡ºï¼Œä¸”ä¸èƒ½åœ¨è®©å‡ºæ—¶ä¼ å‡ºä»»ä½•值; 从钩å­é‡Œè®©å‡ºå¿…须用 lua_yield æ¥ç»“æŸé’©å­çš„è¿è¡Œï¼Œä¸” nresults 必须为零。


lua_sethook

[-0, +0, –]

void lua_sethook (lua_State *L, lua_Hook f, int mask, int count);

设置一个调试用钩å­å‡½æ•°ã€‚

傿•° f 是钩å­å‡½æ•°ã€‚ mask 指定在哪些事件时会调用: 它由下列一组ä½å¸¸é‡æž„æˆ LUA_MASKCALL, LUA_MASKRET, LUA_MASKLINE, LUA_MASKCOUNT。 傿•° count åªåœ¨æŽ©ç ä¸­åŒ…嫿œ‰ LUA_MASKCOUNT æ‰æœ‰æ„义。 对于æ¯ä¸ªäº‹ä»¶ï¼Œé’©å­è¢«è°ƒç”¨çš„æƒ…况解释如下:

é’©å­å¯ä»¥é€šè¿‡è®¾ç½® mask 为零å±è”½ã€‚


lua_setlocal

[-(0|1), +0, –]

const char *lua_setlocal (lua_State *L, const lua_Debug *ar, int n);

设置给定活动记录中的局部å˜é‡çš„值。 傿•° ar 与 n å’Œ lua_getlocal 中的一样 (å‚è§ lua_getlocal )。 lua_setlocal 把栈顶的值赋给å˜é‡ç„¶åŽè¿”回å˜é‡çš„å字。 它会将值从栈顶弹出。

当索引大于活动局部å˜é‡çš„æ•°é‡æ—¶ï¼Œè¿”回 NULL (什么也ä¸å¼¹å‡ºï¼‰ã€‚


lua_setupvalue

[-(0|1), +0, –]

const char *lua_setupvalue (lua_State *L, int funcindex, int n);

设置闭包上值的值。 它把栈顶的值弹出并赋于上值并返回上值的å字。 傿•° funcindex 与 n å’Œ lua_getupvalue 中的一样 (å‚è§ lua_getupvalue )。

å½“ç´¢å¼•å¤§äºŽä¸Šå€¼çš„æ•°é‡æ—¶ï¼Œè¿”回 NULL (什么也ä¸å¼¹å‡ºï¼‰ã€‚


lua_upvalueid

[-0, +0, –]

void *lua_upvalueid (lua_State *L, int funcindex, int n);

返回索引 funcindex 处的闭包中 ç¼–å·ä¸º n 的上值的一个唯一标识符。 傿•° funcindex 与 n å’Œ lua_getupvalue 中的一样 (å‚è§ lua_getupvalue )。 (但 n ä¸å¯ä»¥å¤§äºŽä¸Šå€¼çš„æ•°é‡ï¼‰ã€‚

这些唯一标识符å¯ç”¨äºŽæ£€æµ‹ä¸åŒçš„闭包是å¦å…±äº«äº†ç›¸åŒçš„上值。 共享åŒä¸€ä¸ªä¸Šå€¼çš„ Lua 闭包(å³å®ƒä»¬æŒ‡çš„åŒä¸€ä¸ªå¤–部局部å˜é‡ï¼‰ 会针对这个上值返回相åŒçš„æ ‡è¯†ã€‚


lua_upvaluejoin

[-0, +0, –]

void lua_upvaluejoin (lua_State *L, int funcindex1, int n1,
                                    int funcindex2, int n2);

让索引 funcindex1 处的 Lua 闭包的第 n1 个上值 引用索引 funcindex2 处的 Lua 闭包的第 n2 个上值。

5 – 辅助库

辅助库 æä¾›äº†ä¸€äº›ä¾¿æ·å‡½æ•°ï¼Œæ–¹ä¾¿åœ¨ C 中为 Lua 编程。 基础 API æä¾›äº† C å’Œ Lua 交互用的主è¦å‡½æ•°ï¼Œ 而辅助库则为一些常è§çš„任务æä¾›äº†é«˜é˜¶å‡½æ•°ã€‚

所有辅助库中的函数和类型都定义在头文件 lauxlib.h 中, 它们å‡å¸¦æœ‰å‰ç¼€ luaL_。

辅助库中的所有函数都基于基础 API 实现。 故而它们并没有æä¾›ä»»ä½•基础 API 实现ä¸äº†çš„功能。 虽然如此,使用辅助库å¯ä»¥è®©ä½ çš„ä»£ç æ›´ä¸ºå¥å£®ã€‚

一些辅助库函数会在内部使用一些é¢å¤–的栈空间。 当辅助库使用的栈空间少于五个时, 它们ä¸åŽ»æ£€æŸ¥æ ˆå¤§å°ï¼›è€Œæ˜¯ç®€å•çš„å‡è®¾æ ˆå¤Ÿç”¨ã€‚

一些辅助库中的函数用于检查 C å‡½æ•°çš„å‚æ•°ã€‚ å› ä¸ºé”™è¯¯ä¿¡æ¯æ ¼å¼åŒ–ä¸ºæŒ‡ä»£å‚æ•° (例如,"bad argument #1"), ä½ å°±ä¸è¦æŠŠè¿™äº›å‡½æ•°ç”¨äºŽå‚数之外的值了。

如果检查无法通过, luaL_check* 这些函数一定会抛出错误。

5.1 – 函数和类型

这里我们按字æ¯è¡¨æ¬¡åºåˆ—出了辅助库中的所有函数和类型。


luaL_addchar

[-?, +?, e]

void luaL_addchar (luaL_Buffer *B, char c);

å‘缓存 B (å‚è§ luaL_Buffer ) 添加一个字节 c。


luaL_addlstring

[-?, +?, e]

void luaL_addlstring (luaL_Buffer *B, const char *s, size_t l);

å‘缓存 B (å‚è§ luaL_Buffer ) 添加一个长度为 l 的字符串 s。 这个字符串å¯ä»¥åŒ…å«é›¶ã€‚


luaL_addsize

[-?, +?, e]

void luaL_addsize (luaL_Buffer *B, size_t n);

å‘缓存 B (å‚è§ luaL_Buffer ) 添加一个已在之å‰å¤åˆ¶åˆ°ç¼“冲区(å‚è§ luaL_prepbuffer) 的长度为 n 的字符串。


luaL_addstring

[-?, +?, e]

void luaL_addstring (luaL_Buffer *B, const char *s);

å‘缓存 B (å‚è§ luaL_Buffer ) 添加一个零结尾的字符串 s。


luaL_addvalue

[-1, +?, e]

void luaL_addvalue (luaL_Buffer *B);

å‘缓存 B (å‚è§ luaL_Buffer ) 添加栈顶的一个值,éšåŽå°†å…¶å¼¹å‡ºã€‚

这个函数是æ“作字符串缓存的函数中,唯一一个会(且必须)在栈上放置é¢å¤–元素的。 这个元素将被加入缓存。


luaL_argcheck

[-0, +0, v]

void luaL_argcheck (lua_State *L,
                    int cond,
                    int arg,
                    const char *extramsg);

检查 cond 是å¦ä¸ºçœŸã€‚ 如果ä¸ä¸ºçœŸï¼Œä»¥æ ‡å‡†ä¿¡æ¯å½¢å¼æŠ›å‡ºä¸€ä¸ªé”™è¯¯ (å‚è§ luaL_argerror)。


luaL_argerror

[-0, +0, v]

int luaL_argerror (lua_State *L, int arg, const char *extramsg);

抛出一个错误报告调用的 C 函数的第 arg ä¸ªå‚æ•°çš„问题。 它使用下列标准信æ¯å¹¶åŒ…å«äº†ä¸€æ®µ extramsg 作为注解:

     bad argument #arg to 'funcname' (extramsg)

这个函数永远ä¸ä¼šè¿”回。


luaL_Buffer

typedef struct luaL_Buffer luaL_Buffer;

字符串缓存 的类型。

字符串缓存å¯ä»¥è®© C 代ç åˆ†æ®µæž„造一个 Lua 字符串。 使用模å¼å¦‚下:

如果你预先知é“结果串的长度, ä½ å¯ä»¥è¿™æ ·ä½¿ç”¨ç¼“存:

一般的æ“作过程中,字符串缓存会使用ä¸å®šé‡çš„æ ˆæ§½ã€‚ 因此,在使用缓存中,你ä¸èƒ½å‡å®šç›®å‰æ ˆé¡¶åœ¨å“ªã€‚ 在对缓存æ“作的函数调用间,你都å¯ä»¥ä½¿ç”¨æ ˆï¼Œåªéœ€è¦ä¿è¯æ ˆå¹³è¡¡å³å¯ï¼› å³ï¼Œåœ¨ä½ åšä¸€æ¬¡ç¼“å­˜æ“作调用时,当时的栈ä½ç½®å’Œä¸Šæ¬¡è°ƒç”¨ç¼“å­˜æ“作åŽçš„ä½ç½®ç›¸åŒã€‚ (对于 luaL_addvalue 是个唯一的例外。) 在调用完 luaL_pushresult åŽï¼Œ 栈会æ¢å¤åˆ°ç¼“å­˜åˆå§‹åŒ–æ—¶çš„ä½ç½®ä¸Šï¼Œå¹¶åœ¨é¡¶éƒ¨åŽ‹å…¥æœ€ç»ˆçš„å­—ç¬¦ä¸²ã€‚


luaL_buffinit

[-0, +0, –]

void luaL_buffinit (lua_State *L, luaL_Buffer *B);

åˆå§‹åŒ–缓存 B。 这个函数ä¸ä¼šåˆ†é…任何空间; 缓存必须以一个å˜é‡çš„å½¢å¼å£°æ˜Ž (å‚è§ luaL_Buffer)。


luaL_buffinitsize

[-?, +?, e]

char *luaL_buffinitsize (lua_State *L, luaL_Buffer *B, size_t sz);

等价于调用åºåˆ— luaL_buffinit, luaL_prepbuffsize。


luaL_callmeta

[-0, +(0|1), e]

int luaL_callmeta (lua_State *L, int obj, const char *e);

调用一个元方法。

如果在索引 obj 处的对象有元表, 且元表有域 e 。 è¿™ä¸ªå‡½æ•°ä¼šä»¥è¯¥å¯¹è±¡ä¸ºå‚æ•°è°ƒç”¨è¿™ä¸ªåŸŸã€‚ è¿™ç§æƒ…况下,函数返回真并将调用返回值压栈。 如果那个ä½ç½®æ²¡æœ‰å…ƒè¡¨ï¼Œæˆ–没有对应的元方法, 此函数返回å‡ï¼ˆå¹¶ä¸ä¼šå°†ä»»ä½•东西压栈)。


luaL_checkany

[-0, +0, v]

void luaL_checkany (lua_State *L, int arg);

检查函数在 arg ä½ç½®æ˜¯å¦æœ‰ä»»ä½•类型(包括 nilï¼‰çš„å‚æ•°ã€‚


luaL_checkinteger

[-0, +0, v]

lua_Integer luaL_checkinteger (lua_State *L, int arg);

检查函数的第 arg ä¸ªå‚æ•°æ˜¯å¦æ˜¯ä¸€ä¸ª 整数(或是å¯ä»¥è¢«è½¬æ¢ä¸ºä¸€ä¸ªæ•´æ•°ï¼‰ 并以 lua_Integer 类型返回这个整数值。


luaL_checklstring

[-0, +0, v]

const char *luaL_checklstring (lua_State *L, int arg, size_t *l);

检查函数的第 arg ä¸ªå‚æ•°æ˜¯å¦æ˜¯ä¸€ä¸ª 字符串,并返回该字符串; 如果 l ä¸ä¸º NULL , 将字符串的长度填入 *l。

这个函数使用 lua_tolstring æ¥èŽ·å–结果。 所以该函数有å¯èƒ½å¼•å‘的转æ¢éƒ½åŒæ ·æœ‰æ•ˆã€‚


luaL_checknumber

[-0, +0, v]

lua_Number luaL_checknumber (lua_State *L, int arg);

检查函数的第 arg ä¸ªå‚æ•°æ˜¯å¦æ˜¯ä¸€ä¸ª 数字,并返回这个数字。


luaL_checkoption

[-0, +0, v]

int luaL_checkoption (lua_State *L,
                      int arg,
                      const char *def,
                      const char *const lst[]);

检查函数的第 arg ä¸ªå‚æ•°æ˜¯å¦æ˜¯ä¸€ä¸ª 字符串,并在数组 lst (比如是零结尾的字符串数组) 中查找这个字符串。 返回匹é…到的字符串在数组中的索引å·ã€‚ å¦‚æžœå‚æ•°ä¸æ˜¯å­—符串,或是字符串在数组中匹é…ä¸åˆ°ï¼Œéƒ½å°†æŠ›å‡ºé”™è¯¯ã€‚

如果 def ä¸ä¸º NULL, 函数就把 def 当作默认值。 é»˜è®¤å€¼åœ¨å‚æ•° arg ä¸å­˜åœ¨ï¼Œæˆ–è¯¥å‚æ•°æ˜¯ nil 时生效。

这个函数通常用于将字符串映射为 C 枚举é‡ã€‚ (在 Lua 库中åšè¿™ä¸ªè½¬æ¢å¯ä»¥è®©å…¶ä½¿ç”¨å­—ç¬¦ä¸²ï¼Œè€Œä¸æ˜¯æ•°å­—æ¥åšä¸€äº›é€‰é¡¹ã€‚)


luaL_checkstack

[-0, +0, v]

void luaL_checkstack (lua_State *L, int sz, const char *msg);

将栈空间扩展到 top + sz 个元素。 如果扩展ä¸äº†ï¼Œåˆ™æŠ›å‡ºä¸€ä¸ªé”™è¯¯ã€‚ msg 是用于错误消æ¯çš„é¢å¤–文本 (NULL 表示ä¸éœ€è¦é¢å¤–文本)。


luaL_checkstring

[-0, +0, v]

const char *luaL_checkstring (lua_State *L, int arg);

检查函数的第 arg ä¸ªå‚æ•°æ˜¯å¦æ˜¯ä¸€ä¸ª 字符串并返回这个字符串。

这个函数使用 lua_tolstring æ¥èŽ·å–结果。 所以该函数有å¯èƒ½å¼•å‘的转æ¢éƒ½åŒæ ·æœ‰æ•ˆã€‚


luaL_checktype

[-0, +0, v]

void luaL_checktype (lua_State *L, int arg, int t);

检查函数的第 arg ä¸ªå‚æ•°çš„ç±»åž‹æ˜¯å¦æ˜¯ t。 å‚è§ lua_type 查阅类型 t 的编ç ã€‚


luaL_checkudata

[-0, +0, v]

void *luaL_checkudata (lua_State *L, int arg, const char *tname);

检查函数的第 arg ä¸ªå‚æ•°æ˜¯å¦æ˜¯ä¸€ä¸ªç±»åž‹ä¸º tname çš„ç”¨æˆ·æ•°æ® ï¼ˆå‚è§ luaL_newmetatable )。 它会返回该用户数æ®çš„åœ°å€ ï¼ˆå‚è§ lua_touserdata)。


luaL_checkversion

[-0, +0, –]

void luaL_checkversion (lua_State *L);

æ£€æŸ¥è°ƒç”¨å®ƒçš„å†…æ ¸æ˜¯å¦æ˜¯åˆ›å»ºè¿™ä¸ª Lua çŠ¶æ€æœºçš„内核。 以åŠè°ƒç”¨å®ƒçš„ä»£ç æ˜¯å¦ä½¿ç”¨äº†ç›¸åŒçš„ Lua 版本。 åŒæ—¶ä¹Ÿæ£€æŸ¥è°ƒç”¨å®ƒçš„内核与创建该 Lua çŠ¶æ€æœºçš„内核 是å¦ä½¿ç”¨äº†åŒä¸€ç‰‡åœ°å€ç©ºé—´ã€‚


luaL_dofile

[-0, +?, e]

int luaL_dofile (lua_State *L, const char *filename);

加载并è¿è¡ŒæŒ‡å®šçš„æ–‡ä»¶ã€‚ 它是用下列å®å®šä¹‰å‡ºæ¥ï¼š

     (luaL_loadfile(L, filename) || lua_pcall(L, 0, LUA_MULTRET, 0))

如果没有错误,函数返回å‡ï¼› 有错则返回真。


luaL_dostring

[-0, +?, –]

int luaL_dostring (lua_State *L, const char *str);

加载并è¿è¡ŒæŒ‡å®šçš„字符串。 它是用下列å®å®šä¹‰å‡ºæ¥ï¼š

     (luaL_loadstring(L, str) || lua_pcall(L, 0, LUA_MULTRET, 0))

如果没有错误,函数返回å‡ï¼› 有错则返回真。


luaL_error

[-0, +0, v]

int luaL_error (lua_State *L, const char *fmt, ...);

抛出一个错误。 错误消æ¯çš„æ ¼å¼ç”± fmt 给出。 åŽé¢éœ€æä¾›è‹¥å¹²å‚数, è¿™äº›å‚æ•°éµå¾ª lua_pushfstring 中的规则。 如果能获得相关信æ¯ï¼Œå®ƒè¿˜ä¼šåœ¨æ¶ˆæ¯å‰é¢åŠ ä¸Šé”™è¯¯å‘生时的文件ååŠè¡Œå·ã€‚

这个函数永远ä¸ä¼šè¿”回。 但是在 C 函数中通常éµå¾ªæƒ¯ç”¨æ³•: return luaL_error(args) 。


luaL_execresult

[-0, +3, e]

int luaL_execresult (lua_State *L, int stat);

è¿™ä¸ªå‡½æ•°ç”¨äºŽç”Ÿæˆæ ‡å‡†åº“中和进程相关函数的返回值。 (指 os.execute å’Œ io.close)。


luaL_fileresult

[-0, +(1|3), e]

int luaL_fileresult (lua_State *L, int stat, const char *fname);

è¿™ä¸ªå‡½æ•°ç”¨äºŽç”Ÿæˆæ ‡å‡†åº“中和文件相关的函数的返回值。 (指 (io.open, os.rename, file:seek,等。)。


luaL_getmetafield

[-0, +(0|1), e]

int luaL_getmetafield (lua_State *L, int obj, const char *e);

将索引 obj 处对象的元表中 e 域的值压栈。 如果该对象没有元表,或是该元表没有相关域, 此函数什么也ä¸ä¼šåŽ‹æ ˆå¹¶è¿”å›ž LUA_TNIL。


luaL_getmetatable

[-0, +1, –]

int luaL_getmetatable (lua_State *L, const char *tname);

将注册表中 tname 对应的元表 (å‚è§ luaL_newmetatable)压栈。 如果没有 tname 对应的元表,则将 nil 压栈并返回å‡ã€‚


luaL_getsubtable

[-0, +1, e]

int luaL_getsubtable (lua_State *L, int idx, const char *fname);

ç¡®ä¿ t[fname] 是一张表,并将这张表压栈。 这里的 t 指索引 idx 处的值。 如果它原æ¥å°±æ˜¯ä¸€å¼ è¡¨ï¼Œè¿”回真; å¦åˆ™ä¸ºå®ƒåˆ›å»ºä¸€å¼ æ–°è¡¨ï¼Œè¿”回å‡ã€‚


luaL_gsub

[-0, +1, e]

const char *luaL_gsub (lua_State *L,
                       const char *s,
                       const char *p,
                       const char *r);

将字符串 s 生æˆä¸€ä¸ªå‰¯æœ¬ï¼Œ 并将其中的所有字符串 p 都替æ¢ä¸ºå­—符串 r 。 将结果串压栈并返回它。


luaL_len

[-0, +0, e]

lua_Integer luaL_len (lua_State *L, int index);

以数字形å¼è¿”回给定索引处值的“长度â€ï¼› 它等价于在 Lua 中调用 '#' çš„æ“作 (å‚è§ §3.4.7)。 如果æ“ä½œç»“æžœä¸æ˜¯ä¸€ä¸ªæ•´æ•°ï¼Œåˆ™æŠ›å‡ºä¸€ä¸ªé”™è¯¯ã€‚ ï¼ˆè¿™ç§æƒ…况åªå‘生在触å‘元方法时。)


luaL_loadbuffer

[-0, +1, –]

int luaL_loadbuffer (lua_State *L,
                     const char *buff,
                     size_t sz,
                     const char *name);

等价于 luaL_loadbufferx, å…¶ mode 傿•°ç­‰äºŽ NULL。


luaL_loadbufferx

[-0, +1, –]

int luaL_loadbufferx (lua_State *L,
                      const char *buff,
                      size_t sz,
                      const char *name,
                      const char *mode);

把一段缓存加载为一个 Lua 代ç å—。 这个函数使用 lua_load æ¥åŠ è½½ buff 指å‘的长度为 sz 的内存区。

这个函数和 lua_load 返回值相åŒã€‚ name 作为代ç å—çš„å字,用于调试信æ¯å’Œé”™è¯¯æ¶ˆæ¯ã€‚ mode 字符串的作用åŒå‡½æ•° lua_load。


luaL_loadfile

[-0, +1, e]

int luaL_loadfile (lua_State *L, const char *filename);

等价于 luaL_loadfilex, å…¶ mode 傿•°ç­‰äºŽ NULL。


luaL_loadfilex

[-0, +1, e]

int luaL_loadfilex (lua_State *L, const char *filename,
                                            const char *mode);

把一个文件加载为 Lua 代ç å—。 这个函数使用 lua_load 加载文件中的数æ®ã€‚ 代ç å—çš„å字被命å为 filename。 如果 filename 为 NULL, 它从标准输入加载。 如果文件的第一行以 # 打头,则忽略这一行。

mode 字符串的作用åŒå‡½æ•° lua_load。

此函数的返回值和 lua_load 相åŒï¼Œ ä¸è¿‡å®ƒè¿˜å¯èƒ½äº§ç”Ÿä¸€ä¸ªå«åš LUA_ERRFILE 的出错ç ã€‚è¿™ç§é”™è¯¯å‘生于无法打开或读入文件时,或是文件的模å¼é”™è¯¯ã€‚

å’Œ lua_load 一样,这个函数仅加载代ç å—ä¸è¿è¡Œã€‚


luaL_loadstring

[-0, +1, –]

int luaL_loadstring (lua_State *L, const char *s);

将一个字符串加载为 Lua 代ç å—。 这个函数使用 lua_load 加载一个零结尾的字符串 s。

此函数的返回值和 lua_load 相åŒã€‚

也和 lua_load 一样,这个函数仅加载代ç å—ä¸è¿è¡Œã€‚


luaL_newlib

[-0, +1, e]

void luaL_newlib (lua_State *L, const luaL_Reg l[]);

创建一张新的表,并把列表 l 中的函数注册进去。

它是用下列å®å®žçŽ°çš„ï¼š

     (luaL_newlibtable(L,l), luaL_setfuncs(L,l,0))

数组 l 必须是一个数组,而ä¸èƒ½æ˜¯ä¸€ä¸ªæŒ‡é’ˆã€‚


luaL_newlibtable

[-0, +1, e]

void luaL_newlibtable (lua_State *L, const luaL_Reg l[]);

创建一张新的表,并预分é…足够ä¿å­˜ä¸‹æ•°ç»„ l 内容的空间(但ä¸å¡«å……)。 这是给 luaL_setfuncs 一起用的 (å‚è§ luaL_newlib)。

它以å®å½¢å¼å®žçŽ°ï¼Œ 数组 l 必须是一个数组,而ä¸èƒ½æ˜¯ä¸€ä¸ªæŒ‡é’ˆã€‚


luaL_newmetatable

[-0, +1, e]

int luaL_newmetatable (lua_State *L, const char *tname);

如果注册表中已存在键 tname,返回 0 。 å¦åˆ™ï¼Œ 为用户数æ®çš„元表创建一张新表。 å‘这张表加入 __name = tname 键值对, å¹¶å°† [tname] = new table 添加到注册表中, 返回 1 。 (__name项å¯ç”¨äºŽä¸€äº›é”™è¯¯è¾“出函数。)

è¿™ä¸¤ç§æƒ…å†µéƒ½ä¼šæŠŠæœ€ç»ˆçš„æ³¨å†Œè¡¨ä¸­å…³è” tname 的值压栈。


luaL_newstate

[-0, +0, –]

lua_State *luaL_newstate (void);

创建一个新的 Lua çŠ¶æ€æœºã€‚ 它以一个基于标准 C çš„ realloc 函数实现的内存分é…器 调用 lua_newstate 。 å¹¶æŠŠå¯æ‰“å°ä¸€äº›å‡ºé”™ä¿¡æ¯åˆ°æ ‡å‡†é”™è¯¯è¾“出的 panic 函数(å‚è§ §4.6) 设置好,用于处ç†è‡´å‘½é”™è¯¯ã€‚

è¿”å›žæ–°çš„çŠ¶æ€æœºã€‚ 如果内存分é…失败,则返回 NULL 。


luaL_openlibs

[-0, +0, e]

void luaL_openlibs (lua_State *L);

æ‰“å¼€æŒ‡å®šçŠ¶æ€æœºä¸­çš„æ‰€æœ‰ Lua 标准库。


luaL_optinteger

[-0, +0, v]

lua_Integer luaL_optinteger (lua_State *L,
                             int arg,
                             lua_Integer d);

如果函数的第 arg ä¸ªå‚æ•°æ˜¯ä¸€ä¸ª 整数(或å¯ä»¥è½¬æ¢ä¸ºä¸€ä¸ªæ•´æ•°ï¼‰ï¼Œ 返回该整数。 è‹¥è¯¥å‚æ•°ä¸å­˜åœ¨æˆ–是 nil, 返回 d。 除此之外的情况,抛出错误。


luaL_optlstring

[-0, +0, v]

const char *luaL_optlstring (lua_State *L,
                             int arg,
                             const char *d,
                             size_t *l);

如果函数的第 arg ä¸ªå‚æ•°æ˜¯ä¸€ä¸ª 字符串,返回该字符串。 è‹¥è¯¥å‚æ•°ä¸å­˜åœ¨æˆ–是 nil, 返回 d。 除此之外的情况,抛出错误。

è‹¥ l ä¸ä¸º NULL, 将结果的长度填入 *l 。


luaL_optnumber

[-0, +0, v]

lua_Number luaL_optnumber (lua_State *L, int arg, lua_Number d);

如果函数的第 arg ä¸ªå‚æ•°æ˜¯ä¸€ä¸ª 数字,返回该数字。 è‹¥è¯¥å‚æ•°ä¸å­˜åœ¨æˆ–是 nil, 返回 d。 除此之外的情况,抛出错误。


luaL_optstring

[-0, +0, v]

const char *luaL_optstring (lua_State *L,
                            int arg,
                            const char *d);

如果函数的第 arg ä¸ªå‚æ•°æ˜¯ä¸€ä¸ª 字符串,返回该字符串。 è‹¥è¯¥å‚æ•°ä¸å­˜åœ¨æˆ–是 nil, 返回 d。 除此之外的情况,抛出错误。


luaL_prepbuffer

[-?, +?, e]

char *luaL_prepbuffer (luaL_Buffer *B);

等价于 luaL_prepbuffsize, 其预定义大å°ä¸º LUAL_BUFFERSIZE。


luaL_prepbuffsize

[-?, +?, e]

char *luaL_prepbuffsize (luaL_Buffer *B, size_t sz);

返回一段大å°ä¸º sz 的空间地å€ã€‚ ä½ å¯ä»¥å°†å­—符串å¤åˆ¶å…¶ä¸­ä»¥åŠ åˆ°ç¼“å­˜ B 内 (å‚è§ luaL_Buffer)。 将字符串å¤åˆ¶å…¶ä¸­åŽï¼Œä½ å¿…须调用 luaL_addsize 传入字符串的大å°ï¼Œæ‰ä¼šçœŸæ­£æŠŠå®ƒåŠ å…¥ç¼“å­˜ã€‚


luaL_pushresult

[-?, +1, e]

void luaL_pushresult (luaL_Buffer *B);

结æŸå¯¹ç¼“å­˜ B 的使用,将最终的字符串留在栈顶。


luaL_pushresultsize

[-?, +1, e]

void luaL_pushresultsize (luaL_Buffer *B, size_t sz);

等价于 luaL_addsize,luaL_pushresult。


luaL_ref

[-1, +0, e]

int luaL_ref (lua_State *L, int t);

针对栈顶的对象,创建并返回一个在索引 t 指å‘的表中的 引用 (最åŽä¼šå¼¹å‡ºæ ˆé¡¶å¯¹è±¡ï¼‰ã€‚

此引用是一个唯一的整数键。 åªè¦ä½ ä¸å‘表 t 手工添加整数键, luaL_ref å¯ä»¥ä¿è¯å®ƒè¿”回的键的唯一性。 ä½ å¯ä»¥é€šè¿‡è°ƒç”¨ lua_rawgeti(L, t, r) æ¥æ‰¾å›žç”± r 引用的对象。 函数 luaL_unref 用æ¥é‡Šæ”¾ä¸€ä¸ªå¼•用关è”的对象

如果栈顶的对象是 nil, luaL_ref å°†è¿”å›žå¸¸é‡ LUA_REFNIL。 å¸¸é‡ LUA_NOREF å¯ä»¥ä¿è¯å’Œ luaL_ref 能返回的其它引用值ä¸åŒã€‚


luaL_Reg

typedef struct luaL_Reg {
  const char *name;
  lua_CFunction func;
} luaL_Reg;

用于 luaL_setfuncs 注册函数的数组类型。 name 指函数å,func 是函数指针。 任何 luaL_Reg 数组必须以一对 name 与 func 皆为 NULL 结æŸã€‚


luaL_requiref

[-0, +1, e]

void luaL_requiref (lua_State *L, const char *modname,
                    lua_CFunction openf, int glb);

如果 modname ä¸åœ¨ package.loaded 中, 则调用函数 openf ,并传入字符串 modname。 将其返回值置入 package.loaded[modname]。 这个行为好似该函数通过 require 调用过一样。

如果 glb 为真, åŒæ—¶ä¹Ÿå°†æ¨¡å—设到全局å˜é‡ modname 里。

在栈上留下该模å—的副本。


luaL_setfuncs

[-nup, +0, e]

void luaL_setfuncs (lua_State *L, const luaL_Reg *l, int nup);

把数组 l 中的所有函数 (å‚è§ luaL_Reg) 注册到栈顶的表中(该表在å¯é€‰çš„上值之下,è§ä¸‹é¢çš„解说)。

è‹¥ nup ä¸ä¸ºé›¶ï¼Œ 所有的函数都共享 nup 个上值。 这些值必须在调用之å‰ï¼ŒåŽ‹åœ¨è¡¨ä¹‹ä¸Šã€‚ 这些值在注册完毕åŽéƒ½ä¼šä»Žæ ˆå¼¹å‡ºã€‚


luaL_setmetatable

[-0, +0, –]

void luaL_setmetatable (lua_State *L, const char *tname);

将注册表中 tname å…³è”元表 (å‚è§ luaL_newmetatable) 设为栈顶对象的元表。


luaL_Stream

typedef struct luaL_Stream {
  FILE *f;
  lua_CFunction closef;
} luaL_Stream;

æ ‡å‡†è¾“å…¥è¾“å‡ºåº“ä¸­ç”¨åˆ°çš„æ ‡å‡†æ–‡ä»¶å¥æŸ„结构。

æ–‡ä»¶å¥æŸ„实现为一个完全用户数æ®ï¼Œ 其元表被称为 LUA_FILEHANDLE (LUA_FILEHANDLE 是一个代表真正元表的åå­—çš„å®ï¼‰ã€‚ 这张元表由标准输入输出库(å‚è§ luaL_newmetatable)创建。

用户数æ®å¿…须以结构 luaL_Stream 开头; 此结构其åŽå¯ä»¥åŒ…å«ä»»ä½•其它数æ®ã€‚ f 域指å‘一个 C æ•°æ®æµ (如果它为 NULL è¡¨ç¤ºä¸€ä¸ªæ²¡æœ‰åˆ›å»ºå¥½çš„å¥æŸ„)。 closef 域指å‘ä¸€ä¸ªåœ¨å…³é—­æˆ–å›žæ”¶è¯¥æµæ—¶éœ€è¦è°ƒç”¨çš„ Lua 函数。 è¯¥å‡½æ•°å°†æ”¶åˆ°ä¸€ä¸ªå‚æ•°ï¼Œå³æ–‡ä»¶å¥æŸ„。 它需è¦è¿”回 true(æ“作æˆåŠŸï¼‰æˆ– nil 加错误消æ¯ï¼ˆå‡ºé”™çš„æ—¶å€™ï¼‰ã€‚ 一旦 Lua 调用过这个域,该域的值就会修改为 NULL 以æç¤ºè¿™ä¸ªå¥æŸ„å·²ç»è¢«å…³é—­äº†ã€‚


luaL_testudata

[-0, +0, e]

void *luaL_testudata (lua_State *L, int arg, const char *tname);

此函数和 luaL_checkudata 类似。 但它在测试失败时会返回 NULL è€Œä¸æ˜¯æŠ›å‡ºé”™è¯¯ã€‚


luaL_tolstring

[-0, +1, e]

const char *luaL_tolstring (lua_State *L, int idx, size_t *len);

将给定索引处的 Lua 值转æ¢ä¸ºä¸€ä¸ªç›¸åº”æ ¼å¼çš„ C 字符串。 结果串ä¸ä»…会压栈,还会由函数返回。 如果 len ä¸ä¸º NULL , 它还把字符串长度设到 *len 中。

如果该值有一个带 "__tostring" 域的元表, luaL_tolstring ä¼šä»¥è¯¥å€¼ä¸ºå‚æ•°åŽ»è°ƒç”¨å¯¹åº”çš„å…ƒæ–¹æ³•ï¼Œ 并将其返回值作为结果。


luaL_traceback

[-0, +1, e]

void luaL_traceback (lua_State *L, lua_State *L1, const char *msg,
                     int level);

将栈 L1 的栈回溯信æ¯åŽ‹æ ˆã€‚ 如果 msg ä¸ä¸º NULL ,它会附加到栈回溯信æ¯ä¹‹å‰ã€‚ level 傿•°æŒ‡æ˜Žä»Žç¬¬å‡ å±‚å¼€å§‹åšæ ˆå›žæº¯ã€‚


luaL_typename

[-0, +0, –]

const char *luaL_typename (lua_State *L, int index);

返回给定索引处值的类型å。


luaL_unref

[-0, +0, –]

void luaL_unref (lua_State *L, int t, int ref);

释放索引 t 处表的 ref 引用对象 (å‚è§ luaL_ref )。 æ­¤æ¡ç›®ä¼šä»Žè¡¨ä¸­ç§»é™¤ä»¥è®©å…¶å¼•用的对象å¯è¢«åžƒåœ¾æ”¶é›†ã€‚ 而引用 ref ä¹Ÿè¢«å›žæ”¶å†æ¬¡ä½¿ç”¨ã€‚

如果 ref 为 LUA_NOREF 或 LUA_REFNIL, luaL_unref 什么也ä¸åšã€‚


luaL_where

[-0, +1, e]

void luaL_where (lua_State *L, int lvl);

将一个用于表示 lvl 层栈的控制点ä½ç½®çš„字符串压栈。 这个字符串éµå¾ªä¸‹é¢çš„æ ¼å¼ï¼š

     chunkname:currentline:

0 å±‚æŒ‡å½“å‰æ­£åœ¨è¿è¡Œçš„函数, 1 层指调用正在è¿è¡Œå‡½æ•°çš„函数, 便¬¡ç±»æŽ¨ã€‚

这个函数用于构建错误消æ¯çš„å‰ç¼€ã€‚

6 – 标准库

标准库æä¾›äº†ä¸€äº›æœ‰ç”¨çš„函数, 它们都是直接用 C API 实现的。 其中一些函数æä¾›äº†åŽŸæœ¬è¯­è¨€å°±æœ‰çš„æœåŠ¡ (例如,type 与 getmetatable); å¦ä¸€äº›æä¾›å’Œâ€œå¤–éƒ¨â€æ‰“交é“çš„æœåŠ¡ï¼ˆä¾‹å¦‚ I/O ); 还有些本å¯ä»¥ç”¨ Lua 本身æ¥å®žçŽ°ï¼Œä½†åœ¨ C 中实现å¯ä»¥æ»¡è¶³å…³é”®ç‚¹ä¸Šçš„æ€§èƒ½éœ€æ±‚ (例如 table.sort)。

所有的库都是直接用 C API 实现的,并以分离的 C 模å—å½¢å¼æä¾›ã€‚ ç›®å‰ï¼ŒLua 有下列标准库:

除了基础库和包管ç†åº“, 其它库都把自己的函数放在一张全局表的域中, æˆ–æ˜¯ä»¥å¯¹è±¡æ–¹æ³•çš„å½¢å¼æä¾›ã€‚

è¦ä½¿ç”¨è¿™äº›åº“, C 的宿主程åºéœ€è¦å…ˆè°ƒç”¨ä¸€ä¸‹ luaL_openlibs 这个函数, 这样就能打开所有的标准库。 或者宿主程åºä¹Ÿå¯ä»¥ç”¨ luaL_requiref 分别打开这些库: luaopen_base (基础库), luaopen_package (包管ç†åº“), luaopen_coroutine (å程库), luaopen_string (字符串库), luaopen_utf8 (UTF8 库), luaopen_table (表处ç†åº“), luaopen_math (数学库), luaopen_io (I/O 库), luaopen_os (æ“作系统库), luaopen_debug (调试库)。 这些函数都定义在 lualib.h 中。

6.1 – 基础函数

基础库æä¾›äº† Lua 核心函数。 如果你ä¸å°†è¿™ä¸ªåº“包å«åœ¨ä½ çš„程åºä¸­ï¼Œ 你就需è¦å°å¿ƒæ£€æŸ¥ç¨‹åºæ˜¯å¦éœ€è¦è‡ªå·±æä¾›å…¶ä¸­ä¸€äº›ç‰¹æ€§çš„实现。


assert (v [, message])

å¦‚æžœå…¶å‚æ•° v 的值为å‡ï¼ˆnil 或 false), 它就调用 errorï¼› å¦åˆ™ï¼Œè¿”å›žæ‰€æœ‰çš„å‚æ•°ã€‚ 在错误情况时, message 指那个错误对象; å¦‚æžœä¸æä¾›è¿™ä¸ªå‚æ•°ï¼Œå‚数默认为 "assertion failed!" 。


collectgarbage ([opt [, arg]])

这个函数是垃圾收集器的通用接å£ã€‚ é€šè¿‡å‚æ•° opt 它æä¾›äº†ä¸€ç»„ä¸åŒçš„功能:


dofile ([filename])

打开该å字的文件,并执行文件中的 Lua 代ç å—。 ä¸å¸¦å‚数调用时, dofile 执行标准输入的内容(stdin)。 返回该代ç å—的所有返回值。 对于有错误的情况,dofile 将错误å馈给调用者 (å³ï¼Œdofile 没有è¿è¡Œåœ¨ä¿æŠ¤æ¨¡å¼ä¸‹ï¼‰ã€‚


error (message [, level])

ä¸­æ­¢ä¸Šä¸€æ¬¡ä¿æŠ¤å‡½æ•°è°ƒç”¨ï¼Œ 将错误对象 message 返回。 函数 error 永远ä¸ä¼šè¿”回。

当 message 是一个字符串时,通常 error 会把一些有关出错ä½ç½®çš„ä¿¡æ¯é™„加在消æ¯çš„å‰å¤´ã€‚ level 傿•°æŒ‡æ˜Žäº†æ€Žæ ·èŽ·å¾—å‡ºé”™ä½ç½®ã€‚ 对于 level 1 (默认值),出错ä½ç½®æŒ‡ error 函数调用的ä½ç½®ã€‚ Level 2 将出错ä½ç½®æŒ‡å‘调用 error的函数的函数;以此类推。 ä¼ å…¥ level 0 å¯ä»¥é¿å…在消æ¯å‰æ·»åŠ å‡ºé”™ä½ç½®ä¿¡æ¯ã€‚


_G

一个全局å˜é‡ï¼ˆéžå‡½æ•°ï¼‰ï¼Œ 内部储存有全局环境(å‚è§ §2.2)。 Lua 自己ä¸ä½¿ç”¨è¿™ä¸ªå˜é‡ï¼› 改å˜è¿™ä¸ªå˜é‡çš„值ä¸ä¼šå¯¹ä»»ä½•环境造æˆå½±å“,å之亦然。


getmetatable (object)

如果 object ä¸åŒ…å«å…ƒè¡¨ï¼Œè¿”回 nil 。 å¦åˆ™ï¼Œå¦‚果在该对象的元表中有 "__metatable" 域时返回其关è”值, 没有时返回该对象的元表。


ipairs (t)

返回三个值(迭代函数ã€è¡¨ t ä»¥åŠ 0 ), 如此,以下代ç 

     for i,v in ipairs(t) do body end

将迭代键值对(1,t[1]) ,(2,t[2]), ... ,直到第一个空值。


load (chunk [, chunkname [, mode [, env]]])

加载一个代ç å—。

如果 chunk 是一个字符串,代ç å—指这个字符串。 如果 chunk 是一个函数, load 䏿–­åœ°è°ƒç”¨å®ƒèŽ·å–代ç å—的片断。 æ¯æ¬¡å¯¹ chunk 的调用都必须返回一个字符串紧紧连接在上次调用的返回串之åŽã€‚ 当返回空串ã€nilã€æˆ–是ä¸è¿”回值时,都表示代ç å—结æŸã€‚

如果没有语法错误, 则以函数形å¼è¿”回编译好的代ç å—ï¼› å¦åˆ™ï¼Œè¿”回 nil 加上错误消æ¯ã€‚

如果结果函数有上值, env 被设为第一个上值。 è‹¥ä¸æä¾›æ­¤å‚æ•°ï¼Œå°†å…¨å±€çŽ¯å¢ƒæ›¿ä»£å®ƒã€‚ 所有其它上值åˆå§‹åŒ–为 nil。 (当你加载主代ç å—时候,结果函数一定有且仅有一个上值 _ENV (å‚è§ §2.2))。 然而,如果你加载一个用函数(å‚è§ string.dump, 结果函数å¯ä»¥æœ‰ä»»æ„æ•°é‡çš„上值) 创建出æ¥çš„二进制代ç å—时,所有的上值都是新创建出æ¥çš„。 也就是说它们ä¸ä¼šå’Œåˆ«çš„任何函数共享。

chunkname 在错误消æ¯å’Œè°ƒè¯•消æ¯ä¸­ï¼ˆå‚è§ §4.9),用于代ç å—çš„å字。 å¦‚æžœä¸æä¾›æ­¤å‚æ•°ï¼Œå®ƒé»˜è®¤ä¸ºå­—符串chunk 。 chunk 䏿˜¯å­—符串时,则为 "=(load)" 。

字符串 mode 用于控制代ç å—是文本还是二进制(å³é¢„编译代ç å—)。 它å¯ä»¥æ˜¯å­—符串 "b" (åªèƒ½æ˜¯äºŒè¿›åˆ¶ä»£ç å—), "t" (åªèƒ½æ˜¯æ–‡æœ¬ä»£ç å—), 或 "bt" (å¯ä»¥æ˜¯äºŒè¿›åˆ¶ä¹Ÿå¯ä»¥æ˜¯æ–‡æœ¬ï¼‰ã€‚ 默认值为 "bt"。

Lua ä¸ä¼šå¯¹äºŒè¿›åˆ¶ä»£ç å—åšå¥å£®æ€§æ£€æŸ¥ã€‚ æ¶æ„æž„é€ ä¸€ä¸ªäºŒè¿›åˆ¶å—æœ‰å¯èƒ½æŠŠè§£é‡Šå™¨å¼„崩溃。


loadfile ([filename [, mode [, env]]])

å’Œ load 类似, ä¸è¿‡æ˜¯ä»Žæ–‡ä»¶ filename æˆ–æ ‡å‡†è¾“å…¥ï¼ˆå¦‚æžœæ–‡ä»¶åæœªæä¾›ï¼‰ä¸­èŽ·å–代ç å—。


next (table [, index])

è¿è¡Œç¨‹åºæ¥é历表中的所有域。 ç¬¬ä¸€ä¸ªå‚æ•°æ˜¯è¦éåŽ†çš„è¡¨ï¼Œç¬¬äºŒä¸ªå‚æ•°æ˜¯è¡¨ä¸­çš„æŸä¸ªé”®ã€‚ next 返回该键的下一个键åŠå…¶å…³è”的值。 如果用 nil ä½œä¸ºç¬¬äºŒä¸ªå‚æ•°è°ƒç”¨ next 将返回åˆå§‹é”®åŠå…¶å…³è”值。 当以最åŽä¸€ä¸ªé”®åŽ»è°ƒç”¨ï¼Œæˆ–æ˜¯ä»¥ nil 调用一张空表时, next 返回 nil。 å¦‚æžœä¸æä¾›ç¬¬äºŒä¸ªå‚æ•°ï¼Œå°†è®¤ä¸ºå®ƒå°±æ˜¯ nil。 特别指出,你å¯ä»¥ç”¨ next(t) æ¥åˆ¤æ–­ä¸€å¼ è¡¨æ˜¯å¦æ˜¯ç©ºçš„。

索引在éåŽ†è¿‡ç¨‹ä¸­çš„æ¬¡åºæ— å®šä¹‰ï¼Œ å³ä½¿æ˜¯æ•°å­—索引也是这样。 (如果想按数字次åºé历表,å¯ä»¥ä½¿ç”¨æ•°å­—å½¢å¼çš„ for 。)

当在é历过程中你给表中并ä¸å­˜åœ¨çš„域赋值, next 的行为是未定义的。 然而你å¯ä»¥åŽ»ä¿®æ”¹é‚£äº›å·²å­˜åœ¨çš„åŸŸã€‚ 特别指出,你å¯ä»¥æ¸…除一些已存在的域。


pairs (t)

如果 t 有元方法 __pairs, 以 t ä¸ºå‚æ•°è°ƒç”¨å®ƒï¼Œå¹¶è¿”回其返回的å‰ä¸‰ä¸ªå€¼ã€‚

å¦åˆ™ï¼Œè¿”回三个值:next 函数, 表 tï¼Œä»¥åŠ nil。 因此以下代ç 

     for k,v in pairs(t) do body end

能迭代表 t 中的所有键值对。

å‚è§å‡½æ•° next 中关于迭代过程中修改表的风险。


pcall (f [, arg1, ···])

传入傿•°ï¼Œä»¥ ä¿æŠ¤æ¨¡å¼ è°ƒç”¨å‡½æ•° f 。 è¿™æ„å‘³ç€ f 中的任何错误ä¸ä¼šæŠ›å‡ºï¼› å–而代之的是,pcall 会将错误æ•获到,并返回一个状æ€ç ã€‚ 第一个返回值是状æ€ç ï¼ˆä¸€ä¸ªå¸ƒå°”é‡ï¼‰ï¼Œ 当没有错误时,其为真。 此时,pcall åŒæ ·ä¼šåœ¨çжæ€ç åŽè¿”回所有调用的结果。 在有错误时,pcall 返回 false 加错误消æ¯ã€‚


print (···)

æŽ¥æ”¶ä»»æ„æ•°é‡çš„傿•°ï¼Œå¹¶å°†å®ƒä»¬çš„值打å°åˆ° stdout。 它用 tostring 函数将æ¯ä¸ªå‚数都转æ¢ä¸ºå­—符串。 print ä¸ç”¨äºŽåšæ ¼å¼åŒ–输出。仅作为看一下æŸä¸ªå€¼çš„å¿«æ·æ–¹å¼ã€‚ 多用于调试。 完整的对输出的控制,请使用 string.format ä»¥åŠ io.write。


rawequal (v1, v2)

在ä¸è§¦å‘任何元方法的情况下 检查 v1 是å¦å’Œ v2 相等。 返回一个布尔é‡ã€‚


rawget (table, index)

在ä¸è§¦å‘任何元方法的情况下 èŽ·å– table[index] 的值。 table 必须是一张表; index å¯ä»¥æ˜¯ä»»ä½•值。


rawlen (v)

在ä¸è§¦å‘任何元方法的情况下 返回对象 v 的长度。 v å¯ä»¥æ˜¯è¡¨æˆ–字符串。 它返回一个整数。


rawset (table, index, value)

在ä¸è§¦å‘任何元方法的情况下 å°† table[index] 设为 value。 table 必须是一张表, index å¯ä»¥æ˜¯ nil 与 NaN 之外的任何值。 value å¯ä»¥æ˜¯ä»»ä½• Lua 值。

这个函数返回 table。


select (index, ···)

如果 index 是个数字, é‚£ä¹ˆè¿”å›žå‚æ•°ä¸­ç¬¬ index 个之åŽçš„部分; 负的数字会从åŽå‘å‰ç´¢å¼•(-1 指最åŽä¸€ä¸ªå‚数)。 å¦åˆ™ï¼Œindex 必须是字符串 "#", 此时 select è¿”å›žå‚æ•°çš„个数。


setmetatable (table, metatable)

给指定表设置元表。 (你ä¸èƒ½åœ¨ Lua 中改å˜å…¶å®ƒç±»åž‹å€¼çš„元表,那些åªèƒ½åœ¨ C 里åšã€‚) 如果 metatable 是 nil, 将指定表的元表移除。 如果原æ¥é‚£å¼ å…ƒè¡¨æœ‰ "__metatable" 域,抛出一个错误。

这个函数返回 table。


tonumber (e [, base])

如果调用的时候没有 base, tonumber å°è¯•æŠŠå‚æ•°è½¬æ¢ä¸ºä¸€ä¸ªæ•°å­—。 å¦‚æžœå‚æ•°å·²ç»æ˜¯ä¸€ä¸ªæ•°å­—,或是一个å¯ä»¥è½¬æ¢ä¸ºæ•°å­—的字符串, tonumber 就返回这个数字; å¦åˆ™è¿”回 nil。

字符串的转æ¢ç»“æžœå¯èƒ½æ˜¯æ•´æ•°ä¹Ÿå¯èƒ½æ˜¯æµ®ç‚¹æ•°ï¼Œ è¿™å–决于 Lua çš„è½¬æ¢æ–‡æ³•(å‚è§ §3.1)。 (字符串å¯ä»¥æœ‰å‰ç½®å’ŒåŽç½®çš„空格,å¯ä»¥å¸¦ç¬¦å·ã€‚)

当传入 base 调用它时, e 必须是一个以该进制表示的整数字符串。 进制å¯ä»¥æ˜¯ 2 到 36 ï¼ˆåŒ…å« 2 å’Œ 36)之间的任何整数。 大于 10 è¿›åˆ¶æ—¶ï¼Œå­—æ¯ 'A' (大å°å†™å‡å¯ï¼‰è¡¨ç¤º 10 , 'B' 表示 11ï¼Œä¾æ¬¡åˆ° 'Z' 表示 35 。 如果字符串 e 䏿˜¯è¯¥è¿›åˆ¶ä¸‹çš„åˆæ³•数字, 函数返回 nil。


tostring (v)

å¯ä»¥æŽ¥æ”¶ä»»ä½•类型,它将其转æ¢ä¸ºäººå¯é˜…读的字符串形å¼ã€‚ 浮点数总被转æ¢ä¸ºæµ®ç‚¹æ•°çš„表现形å¼ï¼ˆå°æ•°ç‚¹å½¢å¼æˆ–是指数形å¼ï¼‰ã€‚ (如果想完全控制数字如何被转æ¢ï¼Œå¯ä»¥ä½¿ç”¨ string.format。)

如果 v 有 "__tostring" 域的元表, tostring 会以 v ä¸ºå‚æ•°è°ƒç”¨å®ƒã€‚ 并用它的结果作为返回值。


type (v)

将傿•°çš„类型编ç ä¸ºä¸€ä¸ªå­—符串返回。 函数å¯èƒ½çš„返回值有 "nil" ï¼ˆä¸€ä¸ªå­—ç¬¦ä¸²ï¼Œè€Œä¸æ˜¯ nil 值), "number", "string", "boolean", "table", "function", "thread", "userdata"。


_VERSION

ä¸€ä¸ªåŒ…å«æœ‰å½“å‰è§£é‡Šå™¨ç‰ˆæœ¬å·çš„全局å˜é‡ï¼ˆå¹¶éžå‡½æ•°ï¼‰ã€‚ 当å‰è¿™ä¸ªå˜é‡çš„值为 "Lua 5.3"。


xpcall (f, msgh [, arg1, ···])

这个函数和 pcall 类似。 ä¸è¿‡å®ƒå¯ä»¥é¢å¤–设置一个消æ¯å¤„ç†å™¨ msgh。

6.2 – å程管ç†

关于å程的æ“作作为基础库的一个å­åº“, 被放在一个独立表 coroutine 中。 å程的介ç»å‚è§ §2.6 。


coroutine.create (f)

创建一个主体函数为 f 的新å程。 f 必须是一个 Lua 的函数。 返回这个新å程,它是一个类型为 "thread" 的对象。


coroutine.isyieldable ()

如果正在è¿è¡Œçš„å程å¯ä»¥è®©å‡ºï¼Œåˆ™è¿”回真。

ä¸åœ¨ä¸»çº¿ç¨‹ä¸­æˆ–ä¸åœ¨ä¸€ä¸ªæ— æ³•让出的 C 函数中时,当å‰å程是å¯è®©å‡ºçš„。


coroutine.resume (co [, val1, ···])

开始或继续å程 co çš„è¿è¡Œã€‚ 当你第一次延续一个å程,它会从主体函数处开始è¿è¡Œã€‚ val1, ... è¿™äº›å€¼ä¼šä»¥å‚æ•°å½¢å¼ä¼ å…¥ä¸»ä½“函数。 如果该å程被让出,resume ä¼šé‡æ–°å¯åŠ¨å®ƒï¼› val1, ... è¿™äº›å‚æ•°ä¼šä½œä¸ºè®©å‡ºç‚¹çš„返回值。

如果å程è¿è¡Œèµ·æ¥æ²¡æœ‰é”™è¯¯ï¼Œ resume 返回 true 加上传给 yield 的所有值 (当å程让出), 或是主体函数的所有返回值(当å程中止)。 如果有任何错误å‘生, resume 返回 false 加错误消æ¯ã€‚


coroutine.running ()

è¿”å›žå½“å‰æ­£åœ¨è¿è¡Œçš„å程加一个布尔é‡ã€‚ 如果当å‰è¿è¡Œçš„å程是主线程,其为真。


coroutine.status (co)

以字符串形å¼è¿”回å程 co 的状æ€ï¼š 当å程正在è¿è¡Œï¼ˆå®ƒå°±æ˜¯è°ƒç”¨ status 的那个) ,返回 "running"ï¼› 如果å程调用 yield 挂起或是还没有开始è¿è¡Œï¼Œè¿”回 "suspended"ï¼› 如果å程是活动的,但并ä¸åœ¨è¿è¡Œï¼ˆå³å®ƒæ­£åœ¨å»¶ç»­å…¶å®ƒå程),返回 "normal"ï¼› 如果å程è¿è¡Œå®Œä¸»ä½“å‡½æ•°æˆ–å› é”™è¯¯åœæ­¢ï¼Œè¿”回 "dead"。


coroutine.wrap (f)

创建一个主体函数为 f 的新å程。 f 必须是一个 Lua 的函数。 返回一个函数, æ¯æ¬¡è°ƒç”¨è¯¥å‡½æ•°éƒ½ä¼šå»¶ç»­è¯¥å程。 ä¼ ç»™è¿™ä¸ªå‡½æ•°çš„å‚æ•°éƒ½ä¼šä½œä¸º resume çš„é¢å¤–傿•°ã€‚ å’Œ resume 返回相åŒçš„值, åªæ˜¯æ²¡æœ‰ç¬¬ä¸€ä¸ªå¸ƒå°”é‡ã€‚ 如果å‘生任何错误,抛出这个错误。


coroutine.yield (···)

挂起正在调用的å程的执行。 传递给 yield çš„å‚æ•°éƒ½ä¼šè½¬ä¸º resume çš„é¢å¤–返回值。

6.3 – 模å—

包管ç†åº“æä¾›äº†ä»Ž Lua 中加载模å—的基础库。 åªæœ‰ä¸€ä¸ªå¯¼å‡ºå‡½æ•°ç›´æŽ¥æ”¾åœ¨å…¨å±€çŽ¯å¢ƒä¸­ï¼š require。 所有其它的部分都导出在表 package 中。


require (modname)

加载一个模å—。 这个函数首先查找 package.loaded 表, 检测 modname 是å¦è¢«åŠ è½½è¿‡ã€‚ 如果被加载过,require 返回 package.loaded[modname] 中ä¿å­˜çš„值。 å¦åˆ™ï¼Œå®ƒè¯•ç€ä¸ºæ¨¡å—寻找 加载器 。

require éµå¾ª package.searchers åºåˆ—çš„æŒ‡å¼•æ¥æŸ¥æ‰¾åŠ è½½å™¨ã€‚ 如果改å˜è¿™ä¸ªåºåˆ—,我们å¯ä»¥æ”¹å˜ require 如何查找一个模å—。 下列说明基于 package.searchers 的默认é…置。

首先 require 查找 package.preload[modname] 。 如果这里有一个值,这个值(必须是一个函数)就是那个加载器。 å¦åˆ™ require 使用 Lua 加载器去查找 package.path 的路径。 如果查找失败,接ç€ä½¿ç”¨ C 加载器去查找 package.cpath 的路径。 如果都失败了,å†å°è¯• 一体化 加载器 (å‚è§ package.searchers)。

æ¯æ¬¡æ‰¾åˆ°ä¸€ä¸ªåŠ è½½å™¨ï¼Œrequire éƒ½ç”¨ä¸¤ä¸ªå‚æ•°è°ƒç”¨åŠ è½½å™¨ï¼š modname 和一个在获å–åŠ è½½å™¨è¿‡ç¨‹ä¸­å¾—åˆ°çš„å‚æ•°ã€‚ (如果通过查找文件得到的加载器,这个é¢å¤–傿•°æ˜¯æ–‡ä»¶å。) 如果加载器返回éžç©ºå€¼ï¼Œ require 将这个值赋给 package.loaded[modname]。 如果加载器没能返回一个éžç©ºå€¼ç”¨äºŽèµ‹ç»™ package.loaded[modname], require 会在那里设入 true 。 无论是什么情况,require 都会返回 package.loaded[modname] 的最终值。

如果在加载或è¿è¡Œæ¨¡å—时有错误, æˆ–æ˜¯æ— æ³•ä¸ºæ¨¡å—æ‰¾åˆ°åŠ è½½å™¨ï¼Œ require 都会抛出错误。


package.config

一个æè¿°æœ‰ä¸€äº›ä¸ºåŒ…管ç†å‡†å¤‡çš„编译期é…置信æ¯çš„串。 这个字符串由一系列行构æˆï¼š


package.cpath

这个路径被 require 在 C åŠ è½½å™¨ä¸­åšæœç´¢æ—¶ç”¨åˆ°ã€‚

Lua 用和åˆå§‹åŒ– Lua 路径 package.path 相åŒçš„æ–¹å¼åˆå§‹åŒ– C 路径 package.cpath 。 它会使用环境å˜é‡ LUA_CPATH_5_3 或 环境å˜é‡ LUA_CPATH åˆå§‹åŒ–。 è¦ä¹ˆå°±é‡‡ç”¨ luaconf.h 中定义的默认路径。


package.loaded

用于 require 控制哪些模å—å·²ç»è¢«åŠ è½½çš„è¡¨ã€‚ 当你请求一个 modname 模å—,且 package.loaded[modname] ä¸ä¸ºå‡æ—¶ï¼Œ require 简å•返回储存在内的值。

这个å˜é‡ä»…仅是对真正那张表的引用; 改å˜è¿™ä¸ªå€¼å¹¶ä¸ä¼šæ”¹å˜ require 使用的表。


package.loadlib (libname, funcname)

让宿主程åºåЍæ€é“¾æŽ¥ C 库 libname 。

当 funcname 为 "*", 它仅仅连接该库,让库中的符å·éƒ½å¯¼å‡ºç»™å…¶å®ƒåЍæ€é“¾æŽ¥åº“使用。 å¦åˆ™ï¼Œå®ƒæŸ¥æ‰¾åº“中的函数 funcname ,以 C 函数的形å¼è¿”回这个函数。 因此,funcname å¿…é¡»éµå¾ªåŽŸåž‹ lua_CFunction (å‚è§ lua_CFunction)。

这是一个低阶函数。 它完全绕过了包模å—系统。 å’Œ require ä¸åŒï¼Œ 它ä¸ä¼šåšä»»ä½•路径查询,也ä¸ä¼šè‡ªåŠ¨åŠ æ‰©å±•å。 libname 必须是一个 C 库需è¦çš„完整的文件å,如果有必è¦ï¼Œéœ€è¦æä¾›è·¯å¾„和扩展å。 funcname 必须是 C 库需è¦çš„准确åå­— (这å–决于使用的 C 编译器和链接器)。

这个函数在标准 C 䏭䏿”¯æŒã€‚ 因此,它åªåœ¨éƒ¨åˆ†å¹³å°æœ‰æ•ˆ ( Windows ,Linux ,Mac OS X, Solaris, BSD, åŠ ä¸Šæ”¯æŒ dlfcn 标准的 Unix 系统)。


package.path

这个路径被 require 在 Lua åŠ è½½å™¨ä¸­åšæœç´¢æ—¶ç”¨åˆ°ã€‚

在å¯åŠ¨æ—¶ï¼ŒLua 用环境å˜é‡ LUA_PATH_5_3 或环境å˜é‡ LUA_PATH æ¥åˆå§‹åŒ–这个å˜é‡ã€‚ 或采用 luaconf.h 中的默认路径。 环境å˜é‡ä¸­å‡ºçŽ°çš„æ‰€æœ‰ ";;" éƒ½ä¼šè¢«æ›¿æ¢æˆé»˜è®¤è·¯å¾„。


package.preload

ä¿å­˜æœ‰ä¸€äº›ç‰¹æ®Šæ¨¡å—的加载器 (å‚è§ require)。

这个å˜é‡ä»…仅是对真正那张表的引用; 改å˜è¿™ä¸ªå€¼å¹¶ä¸ä¼šæ”¹å˜ require 使用的表。


package.searchers

用于 require 控制如何加载模å—的表。

这张表内的æ¯ä¸€é¡¹éƒ½æ˜¯ä¸€ä¸ª 查找器函数。 å½“æŸ¥æ‰¾ä¸€ä¸ªæ¨¡å—æ—¶ï¼Œ require 按次åºè°ƒç”¨è¿™äº›æŸ¥æ‰¾å™¨ï¼Œ 并传入模å—å(require çš„å‚æ•°ï¼‰ä½œä¸ºå”¯ä¸€çš„ä¸€ä¸ªå‚æ•°ã€‚ 此函数å¯ä»¥è¿”回å¦ä¸€ä¸ªå‡½æ•°ï¼ˆæ¨¡å—çš„ 加载器)加上å¦ä¸€ä¸ªå°†ä¼ é€’ç»™è¿™ä¸ªåŠ è½½å™¨çš„å‚æ•°ã€‚ 或是返回一个æè¿°ä¸ºä½•没有找到这个模å—的字符串 (或是返回 nil ä»€ä¹ˆä¹Ÿä¸æƒ³è¯´ï¼‰ã€‚

Lua 用四个查找器函数åˆå§‹åŒ–这张表。

第一个查找器就是简å•的在 package.preload 表中查找加载器。

第二个查找器用于查找 Lua 库的加载库。 它使用储存在 package.path 中的路径æ¥åšæŸ¥æ‰¾å·¥ä½œã€‚ 查找过程和函数 package.searchpath æè¿°çš„一致。

第三个查找器用于查找 C 库的加载库。 它使用储存在 package.cpath 中的路径æ¥åšæŸ¥æ‰¾å·¥ä½œã€‚ åŒæ ·ï¼Œ 查找过程和函数 package.searchpath æè¿°çš„一致。 例如,如果 C 路径是这样一个字符串

     "./?.so;./?.dll;/usr/local/?/init.so"

æŸ¥æ‰¾å™¨æŸ¥æ‰¾æ¨¡å— foo ä¼šä¾æ¬¡å°è¯•打开文件 ./foo.so,./foo.dll, ä»¥åŠ /usr/local/foo/init.so。 一旦它找到一个 C 库, 查找器首先使用动æ€é“¾æŽ¥æœºåˆ¶è¿žæŽ¥è¯¥åº“。 ç„¶åŽå°è¯•在该库中找到å¯ä»¥ç”¨ä½œåŠ è½½å™¨çš„ C 函数。 这个 C 函数的å字是 "luaopen_" 紧接模å—å的字符串, å…¶ä¸­å­—ç¬¦ä¸²ä¸­æ‰€æœ‰çš„ä¸‹åˆ’çº¿éƒ½ä¼šè¢«æ›¿æ¢æˆç‚¹ã€‚ 此外,如果模å—å中有横线, 横线åŽé¢çš„部分(包括横线)都被去掉。 例如,如果模å—å为 a.b.c-v2.1, 函数å就是 luaopen_a_b_c。

第四个æœç´¢å™¨æ˜¯ã€€ä¸€ä½“化加载器。 它从 C 路径中查找指定模å—的根å字。 例如,当请求 a.b.c 时, 它将查找 a 这个 C 库。 å¦‚æžœæ‰¾å¾—åˆ°ï¼Œå®ƒä¼šåœ¨é‡Œé¢æ‰¾å­æ¨¡å—的加载函数。 在我们的例å­ä¸­ï¼Œå°±æ˜¯æ‰¾ã€€luaopen_a_b_c。 利用这个机制,å¯ä»¥æŠŠè‹¥å¹² C å­æ¨¡å—打包进å•个库。 æ¯ä¸ªå­æ¨¡å—都å¯ä»¥æœ‰åŽŸæœ¬çš„åŠ è½½å‡½æ•°å。

除了第一个(预加载)æœç´¢å™¨å¤–,æ¯ä¸ªæœç´¢å™¨éƒ½ä¼šè¿”回 它找到的模å—的文件å。 这和 package.searchpath 的返回值一样。 第一个æœç´¢å™¨æ²¡æœ‰è¿”回值。


package.searchpath (name, path [, sep [, rep]])

在指定 path 中æœç´¢æŒ‡å®šçš„ name 。

è·¯å¾„æ˜¯ä¸€ä¸ªåŒ…å«æœ‰ä¸€ç³»åˆ—以分å·åˆ†å‰²çš„ æ¨¡æ¿ æž„æˆçš„字符串。 对于æ¯ä¸ªæ¨¡æ¿ï¼Œéƒ½ä¼šç”¨ name 替æ¢å…¶ä¸­çš„æ¯ä¸ªé—®å·ï¼ˆå¦‚果有的è¯ï¼‰ã€‚ 且将其中的 sep (默认是点)替æ¢ä¸º rep (默认是系统的目录分割符)。 ç„¶åŽå°è¯•打开这个文件å。

例如,如果路径是字符串

     "./?.lua;./?.lc;/usr/local/?/init.lua"

æœç´¢ foo.a 这个åå­—å°† 便¬¡å°è¯•打开文件 ./foo/a.lua , ./foo/a.lcã€€ï¼Œä»¥åŠ /usr/local/foo/a/init.lua。

返回第一个å¯ä»¥ç”¨è¯»æ¨¡å¼æ‰“开(并马上关闭该文件)的文件的å字。 如果ä¸å­˜åœ¨è¿™æ ·çš„æ–‡ä»¶ï¼Œè¿”回 nil 加上错误消æ¯ã€‚ (这æ¡é”™è¯¯æ¶ˆæ¯åˆ—出了所有å°è¯•打开的文件å。)

6.4 – 字符串处ç†

这个库æä¾›äº†å­—符串处ç†çš„通用函数。 例如字符串查找ã€å­ä¸²ã€æ¨¡å¼åŒ¹é…等。 当在 Lua 中对字符串åšç´¢å¼•时,第一个字符从 1 å¼€å§‹è®¡ç®—ï¼ˆè€Œä¸æ˜¯ C 里的 0 )。 索引å¯ä»¥æ˜¯è´Ÿæ•°ï¼Œå®ƒæŒ‡ä»Žå­—符串末尾åå‘è§£æžã€‚ å³ï¼Œæœ€åŽä¸€ä¸ªå­—符在 -1 ä½ç½®å¤„,等等。

字符串库中的所有函数都在表 string 中。 它还将其设置为字符串元表的 __index 域。 因此,你å¯ä»¥ä»¥é¢å‘对象的形å¼ä½¿ç”¨å­—符串函数。 例如,string.byte(s,i) å¯ä»¥å†™æˆ s:byte(i)。

字符串库å‡å®šé‡‡ç”¨å•字节字符编ç ã€‚


string.byte (s [, i [, j]])

返回字符 s[i], s[i+1], ... ,s[j] 的内部数字编ç ã€‚ i 的默认值是 1 ï¼› j 的默认值是 i。 这些索引以函数 string.sub 的规则修正。

æ•°å­—ç¼–ç æ²¡æœ‰å¿…è¦è·¨å¹³å°ã€‚


string.char (···)

接收零或更多的整数。 è¿”å›žå’Œå‚æ•°æ•°é‡ç›¸åŒé•¿åº¦çš„字符串。 其中æ¯ä¸ªå­—符的内部编ç å€¼ç­‰äºŽå¯¹åº”çš„å‚æ•°å€¼ã€‚

æ•°å­—ç¼–ç æ²¡æœ‰å¿…è¦è·¨å¹³å°ã€‚


string.dump (function [, strip])

è¿”å›žåŒ…å«æœ‰ä»¥äºŒè¿›åˆ¶æ–¹å¼è¡¨ç¤ºçš„(一个 二进制代ç å— )指定函数的字符串。 之åŽå¯ä»¥ç”¨ load 调用这个字符串获得 该函数的副本(但是绑定新的上值)。 如果 strip 为真值, 二进制代ç å—䏿ºå¸¦è¯¥å‡½æ•°çš„è°ƒè¯•ä¿¡æ¯ ï¼ˆå±€éƒ¨å˜é‡å,行å·ï¼Œç­‰ç­‰ã€‚)。

带上值的函数åªä¿å­˜ä¸Šå€¼çš„æ•°ç›®ã€‚ å½“ï¼ˆå†æ¬¡ï¼‰åŠ è½½æ—¶ï¼Œè¿™äº›ä¸Šå€¼è¢«æ›´æ–°ä¸º nil 的实例。 (你å¯ä»¥ä½¿ç”¨è°ƒè¯•库按你需è¦çš„æ–¹å¼æ¥åºåˆ—化上值,并é‡è½½åˆ°å‡½æ•°ä¸­ï¼‰


string.find (s, pattern [, init [, plain]])

查找第一个字符串 s 中匹é…到的 pattern (å‚è§ §6.4.1)。 如果找到一个匹é…,find 会返回 s 中关于它起始åŠç»ˆç‚¹ä½ç½®çš„索引; å¦åˆ™ï¼Œè¿”回 nil。 第三个å¯é€‰æ•°å­—傿•° init 指明从哪里开始æœç´¢ï¼› 默认值为 1 ï¼ŒåŒæ—¶å¯ä»¥æ˜¯è´Ÿå€¼ã€‚ 第四个å¯é€‰å‚æ•° plain 为 true 时, 关闭模å¼åŒ¹é…机制。 此时函数仅åšç›´æŽ¥çš„ “查找å­ä¸²â€çš„æ“ä½œï¼Œ 而 pattern 中没有字符被看作魔法字符。 注æ„,如果给定了 plain ,就必须写上 init 。

如果在模å¼ä¸­å®šä¹‰äº†æ•获,æ•获到的若干值也会在两个索引之åŽè¿”回。


string.format (formatstring, ···)

返回ä¸å®šæ•°é‡å‚数的格å¼åŒ–版本, æ ¼å¼åŒ–ä¸²ä¸ºç¬¬ä¸€ä¸ªå‚æ•°ï¼ˆå¿…须是一个字符串)。 æ ¼å¼åŒ–字符串éµå¾ª ISO C 函数 sprintf 的规则。 ä¸åŒç‚¹åœ¨äºŽé€‰é¡¹ *, h, L, l, n, p 䏿”¯æŒï¼Œ å¦å¤–还增加了一个选项 q。 q 选项将一个字符串格å¼åŒ–为两个åŒå¼•å·æ‹¬èµ·ï¼Œå¯¹å†…éƒ¨å­—ç¬¦åšæ°å½“的转义处ç†çš„字符串。 该字符串å¯ä»¥å®‰å…¨çš„被 Lua 解释器读回æ¥ã€‚ 例如,调用

     string.format('%q', 'a string with "quotes" and \n new line')

会产生字符串:

     "a string with \"quotes\" and \
      new line"

选项 A and a (如果有的è¯ï¼‰ï¼Œ E, e, f, G, and g éƒ½æœŸå¾…ä¸€ä¸ªå¯¹åº”çš„æ•°å­—å‚æ•°ã€‚ 选项 c, d, i, o, u, X, and x 则期待一个整数。 选项 q 期待一个字符串; 选项 s 期待一个没有内嵌零的字符串。 如果选项 s å¯¹åº”çš„å‚æ•°ä¸æ˜¯å­—符串,它会用和 tostring ä¸€è‡´çš„è§„åˆ™è½¬æ¢æˆå­—符串。


string.gmatch (s, pattern)

返回一个迭代器函数。 æ¯æ¬¡è°ƒç”¨è¿™ä¸ªå‡½æ•°éƒ½ä¼šç»§ç»­ä»¥ pattern (å‚è§ã€€§6.4.1) 对 s åšåŒ¹é…,并返回所有æ•获到的值。 如果 pattern 中没有指定æ•èŽ·ï¼Œåˆ™æ¯æ¬¡æ•获整个 pattern。

下é¢è¿™ä¸ªä¾‹å­ä¼šå¾ªçŽ¯è¿­ä»£å­—ç¬¦ä¸² s 中所有的å•è¯ï¼Œ å¹¶é€è¡Œæ‰“å°ï¼š

     s = "hello world from Lua"
     for w in string.gmatch(s, "%a+") do
       print(w)
     end

下一个例å­ä»ŽæŒ‡å®šçš„字符串中收集所有的键值对 key=value 置入一张表:

     t = {}
     s = "from=world, to=Lua"
     for k, v in string.gmatch(s, "(%w+)=(%w+)") do
       t[k] = v
     end

对这个函数æ¥è¯´ï¼Œæ¨¡æ¿å‰å¼€å§‹çš„ '^' ä¸ä¼šå½“æˆé”šç‚¹ã€‚因为这样会阻止迭代。


string.gsub (s, pattern, repl [, n])

将字符串 s 中,所有的(或是在 n ç»™å‡ºæ—¶çš„å‰ n 个) pattern (å‚è§ §6.4.1ï¼‰éƒ½æ›¿æ¢æˆ repl ,并返回其副本。 repl å¯ä»¥æ˜¯å­—符串ã€è¡¨ã€æˆ–函数。 gsub 还会在第二个返回值返回一共å‘生了多少次匹é…。 gsub 这个åå­—æ¥æºäºŽ Global SUBstitution 。

如果 repl 是一个字符串,那么把这个字符串作为替æ¢å“。 字符 % 是一个转义符: repl 中的所有形å¼ä¸º %d 的串表示 第 d 个æ•获到的å­ä¸²ï¼Œd å¯ä»¥æ˜¯ 1 到 9 。 串 %0 表示整个匹é…。 串 %% 表示å•个 %。

如果 repl æ˜¯å¼ è¡¨ï¼Œæ¯æ¬¡åŒ¹é…时都会用第一个æ•获物作为键去查这张表。

如果 repl æ˜¯ä¸ªå‡½æ•°ï¼Œåˆ™åœ¨æ¯æ¬¡åŒ¹é…å‘生时都会调用这个函数。 所有æ•获到的å­ä¸²ä¾æ¬¡ä½œä¸ºå‚数传入。

任何情况下,模æ¿ä¸­æ²¡æœ‰è®¾å®šæ•èŽ·éƒ½çœ‹æˆæ˜¯æ•获整个模æ¿ã€‚

如果表的查询结果或函数的返回结果是一个字符串或是个数字, 都将其作为替æ¢ç”¨ä¸²ï¼› 而在返回 false 或 nil 时ä¸ä½œæ›¿æ¢ (å³ä¿ç•™åŒ¹é…å‰çš„原始串)。

这里有一些用例:

     x = string.gsub("hello world", "(%w+)", "%1 %1")
     --> x="hello hello world world"
     
     x = string.gsub("hello world", "%w+", "%0 %0", 1)
     --> x="hello hello world"
     
     x = string.gsub("hello world from Lua", "(%w+)%s*(%w+)", "%2 %1")
     --> x="world hello Lua from"
     
     x = string.gsub("home = $HOME, user = $USER", "%$(%w+)", os.getenv)
     --> x="home = /home/roberto, user = roberto"
     
     x = string.gsub("4+5 = $return 4+5$", "%$(.-)%$", function (s)
           return load(s)()
         end)
     --> x="4+5 = 9"
     
     local t = {name="lua", version="5.3"}
     x = string.gsub("$name-$version.tar.gz", "%$(%w+)", t)
     --> x="lua-5.3.tar.gz"


string.len (s)

接收一个字符串,返回其长度。 空串 "" 的长度为 0 。 内嵌零也统计在内,因此 "a\000bc\000" 的长度为 5 。


string.lower (s)

接收一个字符串,将其中的大写字符都转为å°å†™åŽè¿”回其副本。 其它的字符串ä¸ä¼šæ›´æ”¹ã€‚ 对大写字符的定义å–决于当å‰çš„区域设置。


string.match (s, pattern [, init])

在字符串 s 中找到第一个能用 pattern (å‚è§ §6.4.1)匹é…到的部分。 如果能找到,match 返回其中的æ•获物; å¦åˆ™è¿”回 nil 。 如果 pattern 中未指定æ•获, 返回整个 pattern æ•获到的串。 第三个å¯é€‰æ•°å­—傿•° init 指明从哪里开始æœç´¢ï¼› 它默认为 1 且å¯ä»¥æ˜¯è´Ÿæ•°ã€‚


string.pack (fmt, v1, v2, ···)

返回一个打包了(å³ä»¥äºŒè¿›åˆ¶å½¢å¼åºåˆ—化) v1, v2 等值的二进制字符串。 字符串 fmt 为打包格å¼ï¼ˆå‚è§ §6.4.2)。


string.packsize (fmt)

返回以指定格å¼ç”¨ string.pack 打包的字符串的长度。 æ ¼å¼åŒ–字符串中ä¸å¯ä»¥æœ‰å˜é•¿é€‰é¡¹ 's' 或 'z' (å‚è§ §6.4.2)。


string.rep (s, n [, sep])

返回 n 个字符串 s 以字符串 sep 为分割符连在一起的字符串。 默认的 sep å€¼ä¸ºç©ºå­—ç¬¦ä¸²ï¼ˆå³æ²¡æœ‰åˆ†å‰²ç¬¦ï¼‰ã€‚ 如果 n 䏿˜¯æ­£æ•°åˆ™è¿”回空串。


string.reverse (s)

返回字符串 s 的翻转串。


string.sub (s, i [, j])

返回 s çš„å­ä¸²ï¼Œ 该å­ä¸²ä»Ž i 开始到 j 为止; i å’Œ j 都å¯ä»¥ä¸ºè´Ÿæ•°ã€‚ 如果ä¸ç»™å‡º j ,就当它是 -1 (和字符串长度相åŒï¼‰ã€‚ 特别是, 调用 string.sub(s,1,j) å¯ä»¥è¿”回 s 的长度为 j çš„å‰ç¼€ä¸²ï¼Œ 而 string.sub(s, -i) 返回长度为 i çš„åŽç¼€ä¸²ã€‚

å¦‚æžœåœ¨å¯¹è´Ÿæ•°ç´¢å¼•è½¬ä¹‰åŽ i å°äºŽ 1 çš„è¯ï¼Œå°±ä¿®æ­£å›ž 1 。 如果 j 比字符串的长度还大,就修正为字符串长度。 如果在修正之åŽï¼Œi 大于 j, 函数返回空串。


string.unpack (fmt, s [, pos])

è¿”å›žä»¥æ ¼å¼ fmt (å‚è§ §6.4.2) 打包在字符串 s (å‚è§ string.pack) 中的值。 选项 pos(默认为 1 )标记了从 s 中哪里开始读起。 读完所有的值åŽï¼Œå‡½æ•°è¿”回 s 中第一个未读字节的ä½ç½®ã€‚


string.upper (s)

接收一个字符串,将其中的å°å†™å­—符都转为大写åŽè¿”回其副本。 其它的字符串ä¸ä¼šæ›´æ”¹ã€‚ 对å°å†™å­—符的定义å–决于当å‰çš„区域设置。

6.4.1 – åŒ¹é…æ¨¡å¼

Lua ä¸­çš„åŒ¹é…æ¨¡å¼ç›´æŽ¥ç”¨å¸¸è§„çš„å­—ç¬¦ä¸²æ¥æè¿°ã€‚ 它用于模å¼åŒ¹é…函数 string.find, string.gmatch, string.gsub, string.match。 这一节表述了这些字符串的语法åŠå«ä¹‰ï¼ˆå³å®ƒèƒ½åŒ¹é…到什么)。

字符类:

字符类 用于表示一个字符集åˆã€‚ 下列组åˆå¯ç”¨äºŽå­—符类:

所有å•个字æ¯è¡¨ç¤ºçš„类别(%a,%c,等), è‹¥å°†å…¶å­—æ¯æ”¹ä¸ºå¤§å†™ï¼Œå‡è¡¨ç¤ºå¯¹åº”的补集。 例如,%S 表示所有éžç©ºæ ¼çš„字符。

如何定义字æ¯ã€ç©ºæ ¼ã€æˆ–是其他字符组å–决于当å‰çš„区域设置。 特别注æ„:[a-z] 未必等价于 %l 。

æ¨¡å¼æ¡ç›®ï¼š

æ¨¡å¼æ¡ç›® å¯ä»¥æ˜¯

模å¼ï¼š

æ¨¡å¼ æŒ‡ä¸€ä¸ªæ¨¡å¼æ¡ç›®çš„åºåˆ—。 åœ¨æ¨¡å¼æœ€å‰é¢åŠ ä¸Šç¬¦å· '^' 将锚定从字符串的开始处åšåŒ¹é…。 åœ¨æ¨¡å¼æœ€åŽé¢åŠ ä¸Šç¬¦å· '$' 将使匹é…过程锚定到字符串的结尾。 如果 '^' å’Œ '$' 出现在其它ä½ç½®ï¼Œå®ƒä»¬å‡æ²¡æœ‰ç‰¹æ®Šå«ä¹‰ï¼Œåªè¡¨ç¤ºè‡ªèº«ã€‚

æ•获:

模å¼å¯ä»¥åœ¨å†…éƒ¨ç”¨å°æ‹¬å·æ‹¬èµ·ä¸€ä¸ªå­æ¨¡å¼ï¼› è¿™äº›å­æ¨¡å¼è¢«ç§°ä¸º æ•获物。 å½“åŒ¹é…æˆåŠŸæ—¶ï¼Œç”± æ•获物 匹é…到的字符串中的å­ä¸²è¢«ä¿å­˜èµ·æ¥ç”¨äºŽæœªæ¥çš„用途。 æ•获物以它们左括å·çš„æ¬¡åºæ¥ç¼–å·ã€‚ ä¾‹å¦‚ï¼Œå¯¹äºŽæ¨¡å¼ "(a*(.)%w(%s*))" , 字符串中匹é…到 "a*(.)%w(%s*)" 的部分ä¿å­˜åœ¨ç¬¬ä¸€ä¸ªæ•获物中 ï¼ˆå› æ­¤æ˜¯ç¼–å· 1 ); ç”± "." 匹é…到的字符是 2 å·æ•获物, 匹é…到 "%s*" 的那部分是 3 å·ã€‚

作为一个特例,空的æ•获 () å°†æ•获到当å‰å­—符串的ä½ç½®ï¼ˆå®ƒæ˜¯ä¸€ä¸ªæ•°å­—)。 ä¾‹å¦‚ï¼Œå¦‚æžœå°†æ¨¡å¼ "()aa()" 作用到字符串 "flaaap" 上,将产生两个æ•获物: 3 å’Œ 5 。

6.4.2 – 打包和解包用到的格å¼ä¸²

用于 string.pack, string.packsize, string.unpack çš„ç¬¬ä¸€ä¸ªå‚æ•°ã€‚ 它是一个æè¿°äº†éœ€è¦åˆ›å»ºæˆ–读å–的结构之布局。

æ ¼å¼ä¸²æ˜¯ç”±è½¬æ¢é€‰é¡¹æž„æˆçš„åºåˆ—。 这些转æ¢é€‰é¡¹åˆ—在åŽé¢ï¼š

( "[n]" 表示一个å¯é€‰çš„æ•´æ•°ã€‚) 除填充ã€ç©ºæ ¼ã€é…置项(选项 "xX <=>!")外, æ¯ä¸ªé€‰é¡¹éƒ½å…³è”ä¸€ä¸ªå‚æ•°ï¼ˆå¯¹äºŽ string.pack) 或结果(对于 string.unpack)。

对于选项 "!n", "sn", "in", "In", n å¯ä»¥æ˜¯ 1 到 16 间的整数。 æ‰€æœ‰çš„æ•´æ•°é€‰é¡¹éƒ½å°†åšæº¢å‡ºæ£€æŸ¥ï¼› string.pack 检查æä¾›çš„值是å¦èƒ½ç”¨æŒ‡å®šçš„字长表示; string.unpack 检查读出的值能å¦ç½®å…¥ Lua 整数中。

任何格å¼ä¸²éƒ½å‡è®¾æœ‰ä¸€ä¸ª "!1=" å‰ç¼€ï¼Œ 峿œ€å¤§å¯¹é½ä¸º 1 (无对é½ï¼‰ä¸”采用本地大å°ç«¯è®¾ç½®ã€‚

对é½è¡Œä¸ºæŒ‰å¦‚下规则工作: 对æ¯ä¸ªé€‰é¡¹ï¼Œæ ¼å¼åŒ–时都会填充一些字节直到数æ®ä»Žä¸€ä¸ªç‰¹å®šå移处开始, 这个ä½ç½®æ˜¯è¯¥é€‰é¡¹çš„大å°å’Œæœ€å¤§å¯¹é½æ•°ä¸­è¾ƒå°çš„é‚£ä¸ªæ•°çš„å€æ•°ï¼› 这个较å°å€¼å¿…须是 2 个整数次方。 选项 "c" åŠ "z" ä¸åšå¯¹é½å¤„ç†ï¼› 选项 "s" 对对é½éµå¾ªå…¶å¼€å¤´çš„æ•´æ•°ã€‚

string.pack 用零去填充 (string.unpack 则忽略它)。

6.5 – UTF-8 支æŒ

这个库æä¾›äº†å¯¹ UTF-8 ç¼–ç çš„基础支æŒã€‚ 所有的函数都放在表 utf8 中。 æ­¤åº“ä¸æä¾›é™¤ç¼–ç å¤„ç†ä¹‹å¤–的任何 Unicode 支æŒã€‚ 所有需è¦äº†è§£å­—符å«ä¹‰çš„æ“ä½œï¼Œæ¯”å¦‚å­—ç¬¦åˆ†ç±»ï¼Œéƒ½ä¸åœ¨æ­¤èŒƒç•´ã€‚

除éžå¦æœ‰è¯´æ˜Žï¼Œ 当一个函数需è¦ä¸€ä¸ªå­—节ä½ç½®çš„傿•°æ—¶ï¼Œ 都å‡å®šè¿™ä¸ªä½ç½®è¦ä¹ˆä»Žå­—节åºåˆ—的开始计算, è¦ä¹ˆä»Žå­—符串长度加一的ä½ç½®ç®—。 和字符串库一样,负的索引从字符串末尾计起。


utf8.char (···)

接收零或多个整数, å°†æ¯ä¸ªæ•´æ•°è½¬æ¢æˆå¯¹åº”çš„ UTF-8 字节åºåˆ—,并返回这些åºåˆ—连接到一起的字符串。


utf8.charpattern

用于精确匹é…到一个 UTF-8 字节åºåˆ—的模å¼ï¼ˆæ˜¯ä¸€ä¸ªå­—符串,并éžå‡½æ•°ï¼‰"[\0-\x7F\xC2-\xF4][\x80-\xBF]*" (å‚è§ §6.4.1)。 它å‡å®šå¤„ç†çš„å¯¹è±¡æ˜¯ä¸€ä¸ªåˆæ³•çš„ UTF-8 字符串。


utf8.codes (s)

返回一系列的值,å¯ä»¥è®©

     for p, c in utf8.codes(s) do body end

迭代出字符串 s 中所有的字符。 这里的 p 是ä½ç½®ï¼ˆæŒ‰å­—节数)而 c 是æ¯ä¸ªå­—符的编å·ã€‚ 如果处ç†åˆ°ä¸€ä¸ªä¸åˆæ³•的字节åºåˆ—,将抛出一个错误。


utf8.codepoint (s [, i [, j]])

以整数形å¼è¿”回 s 中 从ä½ç½® i 到 j 间(包括两端) 所有字符的编å·ã€‚ 默认的 i 为 1 ,默认的 j 为 i。 如果碰上ä¸åˆæ³•的字节åºåˆ—,抛出一个错误。


utf8.len (s [, i [, j]])

返回字符串 s 中 从ä½ç½® i 到 j é—´ (包括两端) UTF-8 字符的个数。 默认的 i 为 1 ,默认的 j 为 -1 。 如果它找到任何ä¸åˆæ³•的字节åºåˆ—, 返回å‡å€¼åŠ ä¸Šç¬¬ä¸€ä¸ªä¸åˆæ³•字节的ä½ç½®ã€‚


utf8.offset (s, n [, i])

返回编ç åœ¨ s 中的第 n 个字符的开始ä½ç½®ï¼ˆæŒ‰å­—节数) (从ä½ç½® i 处开始统计)。 è´Ÿ n 则å–在ä½ç½® i å‰çš„字符。 当 n 是éžè´Ÿæ•°æ—¶ï¼Œé»˜è®¤çš„ i 是 1, å¦åˆ™é»˜è®¤ä¸º #s + 1。 因此,utf8.offset(s, -n) å–字符串的倒数第 n 个字符的ä½ç½®ã€‚ 如果指定的字符ä¸åœ¨å…¶ä¸­æˆ–在结æŸç‚¹ä¹‹åŽï¼Œå‡½æ•°è¿”回 nil。

作为特例,当 n 等于 0 时, æ­¤å‡½æ•°è¿”å›žå«æœ‰ s 第 i 字节的那个字符的开始ä½ç½®ã€‚

这个函数å‡å®š s æ˜¯ä¸€ä¸ªåˆæ³•çš„ UTF-8 字符串。

6.6 – 表处ç†

这个库æä¾›äº†è¡¨å¤„ç†çš„通用函数。 所有函数都放在表 table 中。

è®°ä½ï¼Œæ— è®ºä½•时,若一个æ“作需è¦å–表的长度, 这张表必须是一个真åºåˆ—,或是拥有 __len 元方法 (å‚è§ §3.4.7 )。 æ‰€æœ‰çš„å‡½æ•°éƒ½å¿½ç•¥ä¼ å…¥å‚æ•°çš„é‚£å¼ è¡¨ä¸­çš„éžæ•°å­—键。


table.concat (list [, sep [, i [, j]]])

æä¾›ä¸€ä¸ªåˆ—表,其所有元素都是字符串或数字,返回字符串 list[i]..sep..list[i+1] ··· sep..list[j]。 sep 的默认值是空串, i 的默认值是 1 , j 的默认值是 #list 。 如果 i 比 j 大,返回空串。


table.insert (list, [pos,] value)

在 list çš„ä½ç½® pos 处æ’入元素 value , å¹¶åŽç§»å…ƒç´  list[pos], list[pos+1], ···, list[#list] 。 pos 的默认值为 #list+1 , 因此调用 table.insert(t,x) 会将 x æ’在列表 t 的末尾。


table.move (a1, f, e, t [,a2])

将元素从表 a1 移到表 a2。 这个函数åšäº†æ¬¡ç­‰ä»·äºŽåŽé¢è¿™ä¸ªå¤šé‡èµ‹å€¼çš„等价æ“作: a2[t],··· = a1[f],···,a1[e]。 a2 的默认值为 a1。 目标区间å¯ä»¥å’ŒæºåŒºé—´é‡å ã€‚ 索引 f 必须是正数。


table.pack (···)

è¿”å›žç”¨æ‰€æœ‰å‚æ•°ä»¥é”® 1,2, 等填充的新表, å¹¶å°† "n" è¿™ä¸ªåŸŸè®¾ä¸ºå‚æ•°çš„æ€»æ•°ã€‚ 注æ„这张返回的表ä¸ä¸€å®šæ˜¯ä¸€ä¸ªåºåˆ—。


table.remove (list [, pos])

移除 list 中 pos ä½ç½®ä¸Šçš„元素,并返回这个被移除的值。 当 pos 是在 1 到 #list 之间的整数时, 它å‘å‰ç§»åŠ¨å…ƒç´ ã€€list[pos+1], list[pos+2], ···, list[#list] 并删除元素 list[#list]ï¼› 索引 pos å¯ä»¥æ˜¯ #list + 1 ,或在 #list 为 0 æ—¶å¯ä»¥æ˜¯ 0 ï¼› 在这些情况下,函数删除元素 list[pos]。

pos 默认为 #list, 因此调用 table.remove(l) 将移除表 l 的最åŽä¸€ä¸ªå…ƒç´ ã€‚


table.sort (list [, comp])

在表内从 list[1] 到 list[#list] 原地 å¯¹å…¶é—´å…ƒç´ æŒ‰æŒ‡å®šæ¬¡åºæŽ’åºã€‚ 如果æä¾›äº† comp , 它必须是一个å¯ä»¥æŽ¥æ”¶ä¸¤ä¸ªåˆ—è¡¨å†…å…ƒç´ ä¸ºå‚æ•°çš„函数。 å½“ç¬¬ä¸€ä¸ªå…ƒç´ éœ€è¦æŽ’åœ¨ç¬¬äºŒä¸ªå…ƒç´ ä¹‹å‰æ—¶ï¼Œè¿”回真 (因此 not comp(list[i+1],list[i]) 在排åºç»“æŸåŽå°†ä¸ºçœŸï¼‰ã€‚ 如果没有æä¾› comp, 将使用标准 Lua æ“作 < 作为替代å“。

排åºç®—法并ä¸ç¨³å®šï¼› å³å½“两个元素次åºç›¸ç­‰æ—¶ï¼Œå®ƒä»¬åœ¨æŽ’åºåŽçš„相对ä½ç½®å¯èƒ½ä¼šæ”¹å˜ã€‚


table.unpack (list [, i [, j]])

返回列表中的元素。 这个函数等价于

     return list[i], list[i+1], ···, list[j]

i 默认为 1 ,j 默认为 #list。

6.7 – 数学函数

这个库æä¾›äº†åŸºæœ¬çš„æ•°å­¦å‡½æ•°ã€‚ 所以函数都放在表 math 中。 注解有 "integer/float" çš„å‡½æ•°ä¼šå¯¹æ•´æ•°å‚æ•°è¿”回整数结果, 对浮点(或混åˆï¼‰å‚数返回浮点结果。 圆整函数(math.ceil, math.floor, math.modf) 在结果在整数范围内时返回整数,å¦åˆ™è¿”回浮点数。


math.abs (x)

返回 x çš„ç»å¯¹å€¼ã€‚(integer/float)


math.acos (x)

返回 x çš„å余弦值(用弧度表示)。


math.asin (x)

返回 x çš„åæ­£å¼¦å€¼ï¼ˆç”¨å¼§åº¦è¡¨ç¤ºï¼‰ã€‚


math.atan (y [, x])

返回 y/x çš„åæ­£åˆ‡å€¼ï¼ˆç”¨å¼§åº¦è¡¨ç¤ºï¼‰ã€‚ å®ƒä¼šä½¿ç”¨ä¸¤ä¸ªå‚æ•°çš„ç¬¦å·æ¥æ‰¾åˆ°ç»“æžœè½åœ¨å“ªä¸ªè±¡é™ä¸­ã€‚ (å³ä½¿ x 为零时,也å¯ä»¥æ­£ç¡®çš„处ç†ã€‚)

默认的 x 是 1 , 因此调用 math.atan(y) 将返回 y çš„åæ­£åˆ‡å€¼ã€‚


math.ceil (x)

返回ä¸å°äºŽ x çš„æœ€å°æ•´æ•°å€¼ã€‚


math.cos (x)

返回 x 的余弦(å‡å®šå‚数是弧度)。


math.deg (x)

将角 x 从弧度转æ¢ä¸ºè§’度。


math.exp (x)

返回 ex 的值 (e 为自然对数的底)。


math.floor (x)

返回ä¸å¤§äºŽ x 的最大整数值。


math.fmod (x, y)

返回 x 除以 y,将商å‘零圆整åŽçš„余数。 (integer/float)


math.huge

浮点数 HUGE_VAL, 这个数比任何数字值都大。


math.log (x [, base])

返回以指定底的 x 的对数。 默认的 base 是 e (因此此函数返回 x 的自然对数)。


math.max (x, ···)

è¿”å›žå‚æ•°ä¸­æœ€å¤§çš„值, 大å°ç”± Lua æ“作 < 决定。 (integer/float)


math.maxinteger

最大值的整数。


math.min (x, ···)

è¿”å›žå‚æ•°ä¸­æœ€å°çš„值, 大å°ç”± Lua æ“作 < 决定。 (integer/float)


math.mininteger

最å°å€¼çš„æ•´æ•°ã€‚


math.modf (x)

返回 x çš„æ•´æ•°éƒ¨åˆ†å’Œå°æ•°éƒ¨åˆ†ã€‚ 第二个结果一定是浮点数。


math.pi

π 的值。


math.rad (x)

将角 x 从角度转æ¢ä¸ºå¼§åº¦ã€‚


math.random ([m [, n]])

当ä¸å¸¦å‚数调用时, 返回一个 [0,1) åŒºé—´å†…ä¸€è‡´åˆ†å¸ƒçš„æµ®ç‚¹ä¼ªéšæœºæ•°ã€‚ 当以两个整数 m 与 n 调用时, math.random 返回一个 [m, n] 区间 å†…ä¸€è‡´åˆ†å¸ƒçš„æ•´æ•°ä¼ªéšæœºæ•°ã€‚ (值 n-m ä¸èƒ½æ˜¯è´Ÿæ•°ï¼Œä¸”必须在 Lua 整数的表示范围内。) 调用 math.random(n) 等价于 math.random(1,n)。

这个函数是对 C æä¾›çš„ä½éšæœºæ•°å‡½æ•°çš„å°è£…。 对其统计属性ä¸ä½œæ‹…ä¿ã€‚


math.randomseed (x)

把 x è®¾ä¸ºä¼ªéšæœºæ•°å‘生器的“ç§å­â€ï¼š 相åŒçš„ç§å­äº§ç”Ÿç›¸åŒçš„éšæœºæ•°åˆ—。


math.sin (x)

返回 x 的正弦值(å‡å®šå‚数是弧度)。


math.sqrt (x)

返回 x 的平方根。 (你也å¯ä»¥ä½¿ç”¨ä¹˜æ–¹ x^0.5 æ¥è®¡ç®—这个值。)


math.tan (x)

返回 x 的正切值(å‡å®šå‚数是弧度)。


math.tointeger (x)

如果 x å¯ä»¥è½¬æ¢ä¸ºä¸€ä¸ªæ•´æ•°ï¼Œ 返回该整数。 å¦åˆ™è¿”回 nil。


math.type (x)

如果 x 是整数,返回 "integer", 如果它是浮点数,返回 "float", 如果 x 䏿˜¯æ•°å­—,返回 nil。


math.ult (m, n)

如果整数 m å’Œ n ä»¥æ— ç¬¦å·æ•´æ•°å½¢å¼æ¯”较, m 在 n 之下,返回布尔真å¦åˆ™è¿”回å‡ã€‚

6.8 – 输入输出库

I/O 库æä¾›äº†ä¸¤å¥—ä¸åŒé£Žæ ¼çš„æ–‡ä»¶å¤„ç†æŽ¥å£ã€‚ 第一ç§é£Žæ ¼ä½¿ç”¨éšå¼çš„æ–‡ä»¶å¥æŸ„ï¼› 它æä¾›è®¾ç½®é»˜è®¤è¾“入文件åŠé»˜è®¤è¾“出文件的æ“作, 所有的输入输出æ“作都针对这些默认文件。 第二ç§é£Žæ ¼ä½¿ç”¨æ˜¾å¼çš„æ–‡ä»¶å¥æŸ„。

当使用éšå¼æ–‡ä»¶å¥æŸ„时, 所有的æ“作都由表 io æä¾›ã€‚ è‹¥ä½¿ç”¨æ˜¾å¼æ–‡ä»¶å¥æŸ„, io.open ä¼šè¿”å›žä¸€ä¸ªæ–‡ä»¶å¥æŸ„,且所有的æ“ä½œéƒ½ç”±è¯¥æ–‡ä»¶å¥æŸ„çš„æ–¹æ³•æ¥æä¾›ã€‚

表 io 中也æä¾›äº†ä¸‰ä¸ª å’Œ C 中å«ä¹‰ç›¸åŒçš„é¢„å®šä¹‰æ–‡ä»¶å¥æŸ„: io.stdin, io.stdout, ä»¥åŠ io.stderr。 I/O 库永远ä¸ä¼šå…³é—­è¿™äº›æ–‡ä»¶ã€‚

除éžå¦æœ‰è¯´æ˜Žï¼Œ I/O 函数在出错时都返回 nil (第二个返回值为错误消æ¯ï¼Œç¬¬ä¸‰ä¸ªè¿”回值为系统相关的错误ç ï¼‰ã€‚ æˆåŠŸæ—¶è¿”å›žä¸Ž nil ä¸åŒçš„值。 åœ¨éž POSIX 系统上, æ ¹æ®é”™è¯¯ç å–出错误消æ¯çš„过程å¯èƒ½å¹¶éžçº¿ç¨‹å®‰å…¨çš„, 因为这使用了 C 的全局å˜é‡ errno 。


io.close ([file])

等价于 file:close()。 ä¸ç»™å‡º file 时将关闭默认输出文件。


io.flush ()

等价于 io.output():flush()。


io.input ([file])

用文件å调用它时,(以文本模å¼ï¼‰æ¥æ‰“开该å字的文件, å¹¶å°†æ–‡ä»¶å¥æŸ„设为默认输入文件。 å¦‚æžœç”¨æ–‡ä»¶å¥æŸ„去调用它, 就简å•çš„å°†è¯¥å¥æŸ„设为默认输入文件。 如果调用时ä¸ä¼ å‚数,它返回当å‰çš„默认输入文件。

åœ¨å‡ºé”™çš„æƒ…å†µä¸‹ï¼Œå‡½æ•°æŠ›å‡ºé”™è¯¯è€Œä¸æ˜¯è¿”回错误ç ã€‚


io.lines ([filename ···])

ä»¥è¯»æ¨¡å¼æ‰“开指定的文件å并返回一个迭代函数。 此迭代函数的工作方å¼å’Œç”¨ä¸€ä¸ªå·²æ‰“开的文件去调用 file:lines(···) 得到的迭代器相åŒã€‚ 当迭代函数检测到文件结æŸï¼Œ 它ä¸è¿”回值(让循环结æŸï¼‰å¹¶è‡ªåŠ¨å…³é—­æ–‡ä»¶ã€‚

调用 io.lines() (ä¸ä¼ æ–‡ä»¶å) 等价于 io.input():lines("*l")ï¼› å³ï¼Œå®ƒå°†æŒ‰è¡Œè¿­ä»£æ ‡å‡†è¾“入文件。 在此情况下,循环结æŸåŽå®ƒä¸ä¼šå…³é—­æ–‡ä»¶ã€‚

åœ¨å‡ºé”™çš„æƒ…å†µä¸‹ï¼Œå‡½æ•°æŠ›å‡ºé”™è¯¯è€Œä¸æ˜¯è¿”回错误ç ã€‚


io.open (filename [, mode])

这个函数用字符串 mode æŒ‡å®šçš„æ¨¡å¼æ‰“开一个文件。 è¿”å›žæ–°çš„æ–‡ä»¶å¥æŸ„。 当出错时,返回 nil 加错误消æ¯ã€‚

mode 字符串å¯ä»¥æ˜¯ä¸‹åˆ—ä»»æ„值:

mode 字符串å¯ä»¥åœ¨æœ€åŽåŠ ä¸€ä¸ª 'b' , 这会在æŸäº›ç³»ç»Ÿä¸Šä»¥äºŒè¿›åˆ¶æ–¹å¼æ‰“开文件。


io.output ([file])

类似于 io.input。 ä¸è¿‡éƒ½é’ˆå¯¹é»˜è®¤è¾“出文件æ“作。


io.popen (prog [, mode])

è¿™ä¸ªå‡½æ•°å’Œç³»ç»Ÿæœ‰å…³ï¼Œä¸æ˜¯æ‰€æœ‰çš„å¹³å°éƒ½æä¾›ã€‚

用一个分离进程开å¯ç¨‹åº prog, è¿”å›žçš„æ–‡ä»¶å¥æŸ„å¯ç”¨äºŽä»Žè¿™ä¸ªç¨‹åºä¸­è¯»å–æ•°æ® ï¼ˆå¦‚æžœ mode 为 "r",这是默认值) 或是å‘这个程åºå†™å…¥è¾“入(当 mode 为 "w" 时)。


io.read (···)

等价于 io.input():read(···)。


io.tmpfile ()

如果æˆåŠŸï¼Œè¿”å›žä¸€ä¸ªä¸´æ—¶æ–‡ä»¶çš„å¥æŸ„。 è¿™ä¸ªæ–‡ä»¶ä»¥æ›´æ–°æ¨¡å¼æ‰“开,在程åºç»“æŸæ—¶ä¼šè‡ªåŠ¨åˆ é™¤ã€‚


io.type (obj)

检查 obj æ˜¯å¦æ˜¯åˆæ³•çš„æ–‡ä»¶å¥æŸ„。 如果 obj å®ƒæ˜¯ä¸€ä¸ªæ‰“å¼€çš„æ–‡ä»¶å¥æŸ„,返回字符串 "file"。 如果 obj æ˜¯ä¸€ä¸ªå…³é—­çš„æ–‡ä»¶å¥æŸ„,返回字符串 "closed file"。 如果 obj 䏿˜¯æ–‡ä»¶å¥æŸ„,返回 nil 。


io.write (···)

等价于 io.output():write(···)。


file:close ()

关闭 file。 注æ„ï¼Œæ–‡ä»¶åœ¨å¥æŸ„被垃圾回收时会自动关闭, 但是多久以åŽå‘生,时间ä¸å¯é¢„期的。

当关闭用 io.popen 创建出æ¥çš„æ–‡ä»¶å¥æŸ„时, file:close 返回 os.execute 会返回的一样的值。


file:flush ()

将写入的数æ®ä¿å­˜åˆ° file 中。


file:lines (···)

返回一个迭代器函数, æ¯æ¬¡è°ƒç”¨è¿­ä»£å™¨æ—¶ï¼Œéƒ½ä»Žæ–‡ä»¶ä¸­æŒ‰æŒ‡å®šæ ¼å¼è¯»æ•°æ®ã€‚ 如果没有指定格å¼ï¼Œä½¿ç”¨é»˜è®¤å€¼ "l" 。 看一个例å­

     for c in file:lines(1) do body end

会从文件当å‰ä½ç½®å¼€å§‹ï¼Œä¸­ä¸æ–­è¯»å‡ºå­—符。 å’Œ io.lines ä¸åŒï¼Œ 这个函数在循环结æŸåŽä¸ä¼šå…³é—­æ–‡ä»¶ã€‚

åœ¨å‡ºé”™çš„æƒ…å†µä¸‹ï¼Œå‡½æ•°æŠ›å‡ºé”™è¯¯è€Œä¸æ˜¯è¿”回错误ç ã€‚


file:read (···)

读文件 file, 指定的格å¼å†³å®šäº†è¦è¯»ä»€ä¹ˆã€‚ 对于æ¯ç§æ ¼å¼ï¼Œå‡½æ•°è¿”回读出的字符对应的字符串或数字。 è‹¥ä¸èƒ½ä»¥è¯¥æ ¼å¼å¯¹åº”读出数æ®åˆ™è¿”回 nil。 (对于最åŽè¿™ç§æƒ…况, 函数ä¸ä¼šè¯»å‡ºåŽç»­çš„æ ¼å¼ã€‚) 当调用时ä¸ä¼ æ ¼å¼ï¼Œå®ƒä¼šä½¿ç”¨é»˜è®¤æ ¼å¼è¯»ä¸‹ä¸€è¡Œï¼ˆè§ä¸‹é¢æè¿°ï¼‰ã€‚

æä¾›çš„æ ¼å¼æœ‰

æ ¼å¼ "l" å’Œ "L" åªèƒ½ç”¨äºŽæ–‡æœ¬æ–‡ä»¶ã€‚


file:seek ([whence [, offset]])

设置åŠèŽ·å–基于文件开头处计算出的ä½ç½®ã€‚ 设置的ä½ç½®ç”± offset å’Œ whence 字符串 whence 指定的基点决定。基点å¯ä»¥æ˜¯ï¼š

当 seek æˆåŠŸæ—¶ï¼Œè¿”å›žæœ€ç»ˆä»Žæ–‡ä»¶å¼€å¤´è®¡ç®—èµ·çš„æ–‡ä»¶çš„ä½ç½®ã€‚ 当 seek 失败时,返回 nil 加上一个错误æè¿°å­—符串。

whence 的默认值是 "cur", offset 默认为 0 。 因此,调用 file:seek() å¯ä»¥è¿”回文件当å‰ä½ç½®ï¼Œå¹¶ä¸æ”¹å˜å®ƒï¼› 调用 file:seek("set") å°†ä½ç½®è®¾ä¸ºæ–‡ä»¶å¼€å¤´ï¼ˆå¹¶è¿”回 0); 调用 file:seek("end") å°†ä½ç½®è®¾åˆ°æ–‡ä»¶æœ«å°¾ï¼Œå¹¶è¿”回文件大å°ã€‚


file:setvbuf (mode [, size])

设置输出文件的缓冲模å¼ã€‚ æœ‰ä¸‰ç§æ¨¡å¼ï¼š

对于åŽä¸¤ç§æƒ…况,size 以字节数为å•ä½ æŒ‡å®šç¼“å†²åŒºå¤§å°ã€‚ 默认会有一个æ°å½“的大å°ã€‚


file:write (···)

将傿•°çš„值é€ä¸ªå†™å…¥ file。 傿•°å¿…须是字符串或数字。

æˆåŠŸæ—¶ï¼Œå‡½æ•°è¿”å›ž file。 å¦åˆ™è¿”回 nil 加错误æè¿°å­—符串。

6.9 – æ“作系统库

这个库都通过表 os 实现。


os.clock ()

返回程åºä½¿ç”¨çš„æŒ‰ç§’计 CPU 时间的近似值。


os.date ([format [, time]])

è¿”å›žä¸€ä¸ªåŒ…å«æ—¥æœŸåŠæ—¶åˆ»çš„字符串或表。 æ ¼å¼åŒ–方法å–决于所给字符串 format。

如果æä¾›äº† time 傿•°ï¼Œ æ ¼å¼åŒ–这个时间 (这个值的å«ä¹‰å‚è§ os.time 函数)。 å¦åˆ™ï¼Œdate æ ¼å¼åŒ–当剿—¶é—´ã€‚

如果 format 以 '!' 打头, 日期以å调世界时格å¼åŒ–。 在这个å¯é€‰å­—符项之åŽï¼Œ 如果 format 为字符串 "*t", date 返回有åŽç»­åŸŸçš„表: year ï¼ˆå››ä½æ•°å­—),month (1–12),day (1–31), hour (0–23),min (0–59),sec (0–61), wday (星期几,星期天为 1 ), yday (当年的第几天), ä»¥åŠ isdst (å¤ä»¤æ—¶æ ‡è®°ï¼Œä¸€ä¸ªå¸ƒå°”é‡ï¼‰ã€‚ 对于最åŽä¸€ä¸ªåŸŸï¼Œå¦‚果该信æ¯ä¸æä¾›çš„è¯å°±ä¸å­˜åœ¨ã€‚

如果 format å¹¶éž "*t", date 以字符串形å¼è¿”回, æ ¼å¼åŒ–方法éµå¾ª ISO C 函数 strftime 的规则。

如果ä¸ä¼ å‚数调用, date 返回一个åˆç†çš„æ—¥æœŸæ—¶é—´ä¸²ï¼Œ æ ¼å¼å–决于宿主程åºä»¥åŠå½“å‰çš„区域设置 (å³ï¼Œos.date() 等价于 os.date("%c"))。

åœ¨éž POSIX 系统上, 由于这个函数ä¾èµ– C 函数 gmtime å’Œ localtime, 它å¯èƒ½å¹¶éžçº¿ç¨‹å®‰å…¨çš„。


os.difftime (t2, t1)

返回以秒计算的时刻 t1 到 t2 的差值。 (这里的时刻是由 os.time 返回的值)。 在 POSIX,Windows,和其它一些系统中,这个值就等于 t2-t1。


os.execute ([command])

这个函数等价于 ISO C 函数 system。 它调用系统解释器执行 command。 如果命令æˆåŠŸè¿è¡Œå®Œæ¯•,第一个返回值就是 true, å¦åˆ™æ˜¯ nil。 在第一个返回值之åŽï¼Œå‡½æ•°è¿”回一个字符串加一个数字。如下:

如果ä¸å¸¦å‚数调用, os.execute 在系统解释器存在的时候返回真。


os.exit ([code [, close]])

调用 ISO C 函数 exit 终止宿主程åºã€‚ 如果 code 为 true, 返回的状æ€ç æ˜¯ EXIT_SUCCESSï¼› 如果 code 为 false, 返回的状æ€ç æ˜¯ EXIT_FAILUREï¼› 如果 code 是一个数字, 返回的状æ€ç å°±æ˜¯è¿™ä¸ªæ•°å­—。 code 的默认值为 true。

如果第二个å¯é€‰å‚æ•° close 为真, 在退出å‰å…³é—­ Lua çŠ¶æ€æœºã€‚


os.getenv (varname)

返回进程环境å˜é‡ varname 的值, 如果该å˜é‡æœªå®šä¹‰ï¼Œè¿”回 nil 。


os.remove (filename)

删除指定å字的文件(在 POSIX 系统上å¯ä»¥æ˜¯ä¸€ä¸ªç©ºç›®å½•) 如果函数失败,返回 nil 加一个错误æè¿°ä¸²åŠå‡ºé”™ç ã€‚


os.rename (oldname, newname)

å°†å字为 oldname 的文件或目录更å为 newname。 如果函数失败,返回 nil 加一个错误æè¿°ä¸²åŠå‡ºé”™ç ã€‚


os.setlocale (locale [, category])

设置程åºçš„当å‰åŒºåŸŸã€‚ locale 是一个区域设置的系统相关字符串; category 是一个æè¿°æœ‰æ”¹å˜å“ªä¸ªåˆ†ç±»çš„å¯é€‰å­—符串: "all","collate", "ctype", "monetary", "numeric", 或 "time"ï¼› 默认的分类为 "all"。 此函数返回新区域的å字。 如果请求未被获准,返回 nil 。

当 locale 是一个空串, 当å‰åŒºåŸŸè¢«è®¾ç½®ä¸ºä¸€ä¸ªåœ¨å®žçŽ°ä¸­å®šä¹‰å¥½çš„æœ¬åœ°åŒºåŸŸã€‚ 当 locale 为字符串 "C", 当å‰åŒºåŸŸè¢«è®¾ç½®ä¸ºæ ‡å‡† C 区域。

å½“ç¬¬ä¸€ä¸ªå‚æ•°ä¸º nil 时, 此函数仅返回当å‰åŒºåŸŸæŒ‡å®šåˆ†ç±»çš„å字。

由于这个函数ä¾èµ– C 函数 setlocale, 它å¯èƒ½å¹¶éžçº¿ç¨‹å®‰å…¨çš„。


os.time ([table])

当ä¸ä¼ å‚æ•°æ—¶ï¼Œè¿”å›žå½“å‰æ—¶åˆ»ã€‚ 如果传入一张表,就返回由这张表表示的时刻。 这张表必须包å«åŸŸ year,monthï¼ŒåŠ dayï¼› å¯ä»¥åŒ…嫿œ‰ã€€hour (默认为 12 ), min (默认为 0), sec (默认为 0ï¼‰ï¼Œä»¥åŠ isdst (默认为 nil)。 关于这些域的详细æè¿°ï¼Œå‚è§ os.date 函数。

返回值是一个å«ä¹‰ç”±ä½ çš„系统决定的数字。 在 POSIX,Windows,和其它一些系统中, 这个数字统计了从指定时间("epoch")开始ç»åŽ†çš„ç§’æ•°ã€‚ 对于å¦å¤–的系统,其å«ä¹‰æœªå®šä¹‰ï¼Œ ä½ åªèƒ½æŠŠ time 的返回数字用于 os.date å’Œ os.difftime çš„å‚æ•°ã€‚


os.tmpname ()

返回一个å¯ç”¨äºŽä¸´æ—¶æ–‡ä»¶çš„æ–‡ä»¶å字符串。 这个文件在使用å‰å¿…é¡»æ˜¾å¼æ‰“开,ä¸å†ä½¿ç”¨æ—¶éœ€è¦æ˜¾å¼åˆ é™¤ã€‚

在 POSIX 系统上, 这个函数会以此文件å创建一个文件以回é¿å®‰å…¨é£Žé™©ã€‚ (别人å¯èƒ½æœªç»å…许在获å–到这个文件å到创建该文件之间的时刻创建此文件。) 你便—§éœ€è¦åœ¨ä½¿ç”¨å®ƒçš„æ—¶å€™å…ˆæ‰“开,并最åŽåˆ é™¤ï¼ˆå³ä½¿ä½ æ²¡ä½¿ç”¨åˆ°ï¼‰ã€‚

åªæœ‰æœ‰å¯èƒ½ï¼Œä½ æ›´åº”该使用 io.tmpfile, 因为该文件å¯ä»¥åœ¨ç¨‹åºç»“æŸæ—¶è‡ªåŠ¨åˆ é™¤ã€‚

6.10 – 调试库

这个库æä¾›äº† Lua 程åºè°ƒè¯•接å£ï¼ˆ§4.9)的功能。 其中一些函数è¿å了 Lua 代ç çš„基本å‡å®š (例如,ä¸ä¼šä»Žå‡½æ•°ä¹‹å¤–访问函数的局部å˜é‡ï¼› 用户数æ®çš„元表ä¸ä¼šè¢« Lua 代ç ä¿®æ”¹ï¼› Lua 程åºä¸ä¼šå´©æºƒï¼‰ï¼Œ 因此它们有å¯èƒ½å±å®³åˆ°å…¶å®ƒä»£ç çš„安全性。 此外,库里的一些函数å¯èƒ½è¿è¡Œçš„很慢。

这个库里的所有函数都æä¾›åœ¨è¡¨ debug 内。 所有æ“作线程的函数,å¯é€‰çš„ç¬¬ä¸€ä¸ªå‚æ•°éƒ½æ˜¯é’ˆå¯¹çš„线程。 默认值永远是当å‰çº¿ç¨‹ã€‚


debug.debug ()

进入一个用户交互模å¼ï¼Œè¿è¡Œç”¨æˆ·è¾“入的æ¯ä¸ªå­—符串。 使用简å•的命令以åŠå…¶å®ƒè°ƒè¯•设置,用户å¯ä»¥æ£€é˜…全局å˜é‡å’Œå±€éƒ¨å˜é‡ï¼Œ 改å˜å˜é‡çš„值,计算一些表达å¼ï¼Œç­‰ç­‰ã€‚ è¾“å…¥ä¸€è¡Œä»…åŒ…å« cont 的字符串将结æŸè¿™ä¸ªå‡½æ•°ï¼Œ 这样调用者就å¯ä»¥ç»§ç»­å‘下è¿è¡Œã€‚

注æ„,debug.debug 输入的命令在文法上并没有内嵌到任何函数中, å› æ­¤ä¸èƒ½ç›´æŽ¥åŽ»è®¿é—®å±€éƒ¨å˜é‡ã€‚


debug.gethook ([thread])

返回三个表示线程钩å­è®¾ç½®çš„值: 当å‰é’©å­å‡½æ•°ï¼Œå½“å‰é’©å­æŽ©ç ï¼Œå½“å‰é’©å­è®¡æ•° (debug.sethook 设置的那些)。


debug.getinfo ([thread,] f [, what])

返回关于一个函数信æ¯çš„表。 ä½ å¯ä»¥ç›´æŽ¥æä¾›è¯¥å‡½æ•°ï¼Œ 也å¯ä»¥ç”¨ä¸€ä¸ªæ•°å­— f 表示该函数。 æ•°å­— f 表示è¿è¡Œåœ¨æŒ‡å®šçº¿ç¨‹çš„调用栈对应层次上的函数: 0 层表示当å‰å‡½æ•°ï¼ˆgetinfo 自身); 1 层表示调用 getinfo 的函数 ï¼ˆé™¤éžæ˜¯å°¾è°ƒç”¨ï¼Œè¿™ç§æƒ…况ä¸è®¡å…¥æ ˆï¼‰ï¼›ç­‰ç­‰ã€‚ 如果 f 是一个比活动函数数é‡è¿˜å¤§çš„æ•°å­—, getinfo 返回 nil。

åªæœ‰å­—符串 what 中有æè¿°è¦å¡«å……哪些项, 返回的表å¯ä»¥åŒ…å« lua_getinfo 能返回的所有项。 what 默认是返回æä¾›çš„é™¤åˆæ³•行å·è¡¨å¤–的所有信æ¯ã€‚ 对于选项 'f' ,会在å¯èƒ½çš„æƒ…况下,增加 func 域ä¿å­˜å‡½æ•°è‡ªèº«ã€‚ 对于选项 'L' ,会在å¯èƒ½çš„æƒ…况下,增加 activelines 域ä¿å­˜åˆæ³•行å·è¡¨ã€‚

例如,è¡¨è¾¾å¼ debug.getinfo(1,"n") 返回带有当å‰å‡½æ•°åå­—ä¿¡æ¯çš„表(如果找的到åå­—çš„è¯ï¼‰ï¼Œ è¡¨è¾¾å¼ debug.getinfo(print) 返回关于 print 函数的 åŒ…å«æœ‰æ‰€æœ‰èƒ½æä¾›ä¿¡æ¯çš„表。


debug.getlocal ([thread,] f, local)

此函数返回在栈的 f 层处函数的索引为 local 的局部å˜é‡ çš„å字和值。 这个函数ä¸ä»…用于访问显å¼å®šä¹‰çš„局部å˜é‡ï¼Œä¹ŸåŒ…括形å‚ã€ä¸´æ—¶å˜é‡ç­‰ã€‚

ç¬¬ä¸€ä¸ªå½¢å‚æˆ–是定义的第一个局部å˜é‡çš„索引为 1 , ç„¶åŽéµå¾ªåœ¨ä»£ç ä¸­å®šä¹‰æ¬¡åºï¼Œä»¥æ¬¡ç±»æŽ¨ã€‚ 其中åªè®¡ç®—函数当å‰ä½œç”¨åŸŸçš„æ´»åЍå˜é‡ã€‚ 负索引指å¯å˜å‚æ•°ï¼› -1 指第一个å¯å˜å‚数。 如果该索引处没有å˜é‡ï¼Œå‡½æ•°è¿”回 nil。 若指定的层次越界,抛出错误。 (你å¯ä»¥è°ƒç”¨ debug.getinfo æ¥æ£€æŸ¥å±‚次是å¦åˆæ³•。)

以 '(' (开括å·ï¼‰æ‰“头的å˜é‡å表示没有åå­—çš„å˜é‡ (比如是循环控制用到的控制å˜é‡ï¼Œ 或是去除了调试信æ¯çš„代ç å—)。

傿•° f 也å¯ä»¥æ˜¯ä¸€ä¸ªå‡½æ•°ã€‚ è¿™ç§æƒ…况下,getlocal 仅返回函数形å‚çš„å字。


debug.getmetatable (value)

返回给定 value 的元表。 若其没有元表则返回 nil 。


debug.getregistry ()

返回注册表(å‚è§ §4.5)。


debug.getupvalue (f, up)

此函数返回函数 f 的第 up 个上值的å字和值。 如果该函数没有那个上值,返回 nil 。

以 '(' (开括å·ï¼‰æ‰“头的å˜é‡å表示没有åå­—çš„å˜é‡ (去除了调试信æ¯çš„代ç å—)。


debug.getuservalue (u)

返回关è”在 u 上的 Lua 值。 如果 u å¹¶éžç”¨æˆ·æ•°æ®ï¼Œè¿”回 nil。


debug.sethook ([thread,] hook, mask [, count])

将一个函数作为钩å­å‡½æ•°è®¾å…¥ã€‚ 字符串 mask ä»¥åŠæ•°å­— count 决定了钩å­å°†åœ¨ä½•时调用。 æŽ©ç æ˜¯ç”±ä¸‹åˆ—å­—ç¬¦ç»„åˆæˆçš„字符串,æ¯ä¸ªå­—符有其å«ä¹‰ï¼š

此外, 传入一个ä¸ä¸ºé›¶çš„ count , é’©å­å°†åœ¨æ¯è¿è¡Œ count æ¡æŒ‡ä»¤æ—¶è°ƒç”¨ã€‚

如果ä¸ä¼ å…¥å‚数, debug.sethook 关闭钩å­ã€‚

当钩å­è¢«è°ƒç”¨æ—¶ï¼Œ ç¬¬ä¸€ä¸ªå‚æ•°æ˜¯è§¦å‘这次调用的事件: "call" (或 "tail call"), "return", "line", "count"。 对于行事件, é’©å­çš„ç¬¬äºŒä¸ªå‚æ•°æ˜¯æ–°çš„行å·ã€‚ 在钩å­å†…,你å¯ä»¥è°ƒç”¨ getinfo ,指定第 2 层, æ¥èŽ·å¾—æ­£åœ¨è¿è¡Œçš„å‡½æ•°çš„è¯¦ç»†ä¿¡æ¯ ï¼ˆ0 层指 getinfo 函数, 1 层指钩å­å‡½æ•°ï¼‰ã€‚


debug.setlocal ([thread,] level, local, value)

这个函数将 value 赋给 栈上第 level 层函数的第 local 个局部å˜é‡ã€‚ 如果没有那个å˜é‡ï¼Œå‡½æ•°è¿”回 nil 。 如果 level 越界,抛出一个错误。 (你å¯ä»¥è°ƒç”¨ debug.getinfo æ¥æ£€æŸ¥å±‚次是å¦åˆæ³•。) å¦åˆ™ï¼Œå®ƒè¿”回局部å˜é‡çš„å字。

关于å˜é‡ç´¢å¼•å’Œå字,å‚è§ debug.getlocal。


debug.setmetatable (value, table)

å°† value 的元表设为 table (å¯ä»¥æ˜¯ nil)。 返回 value。


debug.setupvalue (f, up, value)

这个函数将 value 设为函数 f 的第 up 个上值。 如果函数没有那个上值,返回 nil å¦åˆ™ï¼Œè¿”回该上值的å字。


debug.setuservalue (udata, value)

å°† value 设为 udata 的关è”值。 udata 必须是一个完全用户数æ®ã€‚

返回 udata。


debug.traceback ([thread,] [message [, level]])

如果 message æœ‰ï¼Œä¸”ä¸æ˜¯å­—符串或 nil, 函数ä¸åšä»»ä½•处ç†ç›´æŽ¥è¿”回 message。 å¦åˆ™ï¼Œå®ƒè¿”回调用栈的栈回溯信æ¯ã€‚ 字符串å¯é€‰é¡¹ message 被添加在栈回溯信æ¯çš„开头。 æ•°å­—å¯é€‰é¡¹ level 指明从栈的哪一层开始回溯 (默认为 1 ,å³è°ƒç”¨ traceback 的那里)。


debug.upvalueid (f, n)

返回指定函数第 n 个上值的唯一标识符(一个轻é‡ç”¨æˆ·æ•°æ®ï¼‰ã€‚

这个唯一标识符å¯ä»¥è®©ç¨‹åºæ£€æŸ¥ä¸¤ä¸ªä¸åŒçš„闭包是å¦å…±äº«äº†ä¸Šå€¼ã€‚ è‹¥ Lua 闭包之间共享的是åŒä¸€ä¸ªä¸Šå€¼ ï¼ˆå³æŒ‡å‘一个外部局部å˜é‡ï¼‰ï¼Œä¼šè¿”回相åŒçš„æ ‡è¯†ç¬¦ã€‚


debug.upvaluejoin (f1, n1, f2, n2)

让 Lua 闭包 f1 的第 n1 个上值 引用 Lua 闭包 f2 的第 n2 个上值。

7 – 独立版 Lua

虽然 Lua 被设计æˆä¸€é—¨æ‰©å±•å¼è¯­è¨€ï¼Œç”¨äºŽåµŒå…¥ä¸€ä¸ªå®¿ä¸»ç¨‹åºã€‚ 但ç»å¸¸ä¹Ÿä¼šè¢«å½“æˆç‹¬ç«‹è¯­è¨€ä½¿ç”¨ã€‚ 独立版的 Lua è¯­è¨€è§£é‡Šå™¨éšæ ‡å‡†åŒ…å‘å¸ƒï¼Œå°±å« lua。 独立版解释器ä¿ç•™äº†æ‰€æœ‰çš„æ ‡å‡†åº“åŠè°ƒè¯•库。 其命令行用法为:

     lua [options] [script [args]]

选项有:

在处ç†å®Œé€‰é¡¹åŽï¼Œlua è¿è¡ŒæŒ‡å®šçš„ 脚本。 如果ä¸å¸¦å‚数调用, 在标准输入(stdin)是终端时,lua 的行为和 lua -v -i 相åŒã€‚ å¦åˆ™ç›¸å½“于 lua - 。

如果调用时ä¸å¸¦é€‰é¡¹ -E, 解释器会在è¿è¡Œä»»ä½•傿•°å‰ï¼Œæ£€æŸ¥çŽ¯å¢ƒå˜é‡ LUA_INIT_5_3 ï¼ˆæˆ–åœ¨ç‰ˆæœ¬åæœªå®šä¹‰æ—¶ï¼Œæ£€æŸ¥ LUA_INIT )。 如果该å˜é‡å†…存格å¼ä¸º @filename, lua 执行该文件。 å¦åˆ™ï¼Œlua 执行该字符串。

如果调用时有选项 -E, 除了忽略 LUA_INIT 外, Lua 还忽略 LUA_PATH 与 LUA_CPATH 的值。 将 package.path 和 package.cpath 的值设为定义在 luaconf.h 中的默认路径。

除 -i 与 -E 外所有的选项都按次åºå¤„ç†ã€‚ 例如,这样调用

     $ lua -e'a=1' -e 'print(a)' script.lua

将先把 a 设为 1ï¼Œç„¶åŽæ‰“å° a 的值, 最åŽè¿è¡Œæ–‡ä»¶ script.lua å¹¶ä¸å¸¦å‚数。 (这里的 $ 是命令行æç¤ºã€‚你的命令行æç¤ºå¯èƒ½ä¸ä¸€æ ·ã€‚)

在è¿è¡Œä»»ä½•代ç å‰ï¼Œ lua ä¼šå°†æ‰€æœ‰å‘½ä»¤è¡Œä¼ å…¥çš„å‚æ•°æ”¾åˆ°ä¸€å¼ å…¨å±€è¡¨ arg 中。 脚本的å字放在索引 0 的地方, 脚本ååŽç´§è·Ÿçš„ç¬¬ä¸€ä¸ªå‚æ•°åœ¨ç´¢å¼• 1 å¤„ï¼Œä¾æ¬¡ç±»æŽ¨ã€‚ 在脚本åå‰é¢çš„任何傿•° (å³è§£é‡Šå™¨çš„å字以åŠå„选项) 放在负索引处。 例如,调用

     $ lua -la b.lua t1 t2

这张表是这样的:

     arg = { [-2] = "lua", [-1] = "-la",
             [0] = "b.lua",
             [1] = "t1", [2] = "t2" }

如果调用中没æä¾›è„šæœ¬å, 解释器的å字就放在索引 0 处,åŽé¢æŽ¥ç€å…¶å®ƒå‚数。 例如,调用

     $ lua -e "print(arg[1])"

将打å°å‡º "-e" 。 如果æä¾›äº†è„šæœ¬å, 就以 arg[1], ···, arg[#arg] ä¸ºå‚æ•°è°ƒç”¨è„šæœ¬ã€‚ (和 Lua 所有的代ç å—一样, 脚本被编译æˆä¸€ä¸ªå¯å˜å‚数函数。)

在交互模å¼ä¸‹ï¼Œ Lua 䏿–­çš„æ˜¾ç¤ºæç¤ºç¬¦ï¼Œå¹¶ç­‰å¾…下一行输入。 一旦读到一行, é¦–å…ˆè¯•ç€æŠŠè¿™è¡Œè§£é‡Šä¸ºä¸€ä¸ªè¡¨è¾¾å¼ã€‚ 如果æˆåŠŸè§£é‡Šï¼Œå°±æ‰“å°è¡¨è¾¾å¼çš„值。 å¦åˆ™ï¼Œå°†è¿™è¡Œè§£é‡Šä¸ºè¯­å¥ã€‚ 如果你写了一行未完æˆçš„语å¥ï¼Œ 解释器会用一个ä¸åŒçš„æç¤ºç¬¦æ¥ç­‰å¾…你写完。

å½“è„šæœ¬ä¸­å‡ºçŽ°äº†æœªä¿æŠ¤çš„é”™è¯¯ï¼Œ è§£é‡Šå™¨å‘æ ‡å‡†é”™è¯¯æµæŠ¥å‘Šé”™è¯¯ã€‚ 如果错误对象并éžä¸€ä¸ªå­—ç¬¦ä¸²ï¼Œä½†æ˜¯å´æœ‰å…ƒæ–¹æ³• __tostring çš„è¯ï¼Œ è§£é‡Šå™¨ä¼šè°ƒç”¨è¿™ä¸ªå…ƒæ–¹æ³•ç”Ÿæˆæœ€ç»ˆçš„æ¶ˆæ¯ã€‚ å¦åˆ™ï¼Œè§£é‡Šå™¨å°†é”™è¯¯å¯¹è±¡è½¬æ¢ä¸ºä¸€ä¸ªå­—符串,并把栈回溯信æ¯åŠ åœ¨å‰é¢ã€‚

如果正常结æŸè¿è¡Œï¼Œ 解释器会关闭主 Lua çŠ¶æ€æœº (å‚è§ lua_close)。 脚本å¯ä»¥é€šè¿‡è°ƒç”¨ os.exit æ¥ç»“æŸï¼Œä»¥å›žé¿è¿™ä¸ªæ­¥éª¤ã€‚

为了让 Lua å¯ä»¥ç”¨äºŽ Unix 系统的脚本解释器。 独立版解释器会忽略代ç å—的以 # 打头的第一行。 因此,Lua 脚本å¯ä»¥é€šè¿‡ chmod +x ä»¥åŠ #! å½¢å¼å˜æˆä¸€ä¸ªå¯æ‰§è¡Œæ–‡ä»¶ã€‚ 类似这样

     #!/usr/local/bin/lua

(当然, Lua 解释器的ä½ç½®å¯¹äºŽä½ çš„æœºå™¨æ¥è¯´å¯èƒ½ä¸ä¸€æ ·ã€‚ 如果 lua 在你的 PATH 中, 写æˆ

     #!/usr/bin/env lua

更为通用。)

8 – 与之å‰ç‰ˆæœ¬ä¸å…¼å®¹çš„地方

这里我们列出了把程åºä»Ž Lua 5.2 è¿ç§»åˆ° Lua 5.3 会碰到的ä¸å…¼å®¹çš„地方。 ä½ å¯ä»¥åœ¨ç¼–译 Lua 时定义一些æ°å½“的选项(å‚è§æ–‡ä»¶ luaconf.h), æ¥å›žé¿ä¸€äº›ä¸å…¼å®¹æ€§ã€‚ 然而,这些兼容选项以åŽä¼šç§»é™¤ã€‚

Lua 的版本更替总是会修改一些 C API å¹¶æ¶‰åŠæºä»£ç çš„æ”¹å˜ã€‚ 例如一些常é‡çš„æ•°å­—å€¼ï¼Œç”¨å®æ¥å®žçŽ°ä¸€äº›å‡½æ•°ã€‚ 因此,你ä¸èƒ½å‡è®¾åœ¨ä¸åŒçš„ Lua 版本间å¯ä»¥åšåˆ°äºŒè¿›åˆ¶å…¼å®¹ã€‚ 当你使用新版时,一定è¦å°†ä½¿ç”¨äº† Lua API 的客户程åºé‡æ–°ç¼–译。

åŒæ ·ï¼ŒLua 版本更替还会改å˜é¢„编译代ç å—的内部呈现方å¼ï¼› 在ä¸åŒçš„ Lua 版本间,预编译代ç å—ä¸å…¼å®¹ã€‚

官方å‘布版的标准路径也å¯èƒ½éšç‰ˆæœ¬å˜åŒ–。

8.1 – è¯­è¨€çš„å˜æ›´

8.2 – åº“çš„å˜æ›´

8.3 – API çš„å˜æ›´

9 – Lua 的完整语法

这是一份采用扩展 BNF æè¿°çš„ Lua 完整语法。 在扩展 BNF 中, {A} 表示 0 或多个 A , [A] 表示一个å¯é€‰çš„ A 。 (æ“作符优先级,å‚è§ §3.4.8ï¼› 对于最终符å·ï¼Œå字,数字,字符串字é¢é‡çš„解释,å‚è§ §3.1。)


	chunk ::= block

	block ::= {stat} [retstat]

	stat ::=  ‘;’ | 
		 varlist ‘=’ explist | 
		 functioncall | 
		 label | 
		 break | 
		 goto Name | 
		 do block end | 
		 while exp do block end | 
		 repeat block until exp | 
		 if exp then block {elseif exp then block} [else block] end | 
		 for Name ‘=’ exp ‘,’ exp [‘,’ exp] do block end | 
		 for namelist in explist do block end | 
		 function funcname funcbody | 
		 local function Name funcbody | 
		 local namelist [‘=’ explist] 

	retstat ::= return [explist] [‘;’]

	label ::= ‘::’ Name ‘::’

	funcname ::= Name {‘.’ Name} [‘:’ Name]

	varlist ::= var {‘,’ var}

	var ::=  Name | prefixexp ‘[’ exp ‘]’ | prefixexp ‘.’ Name 

	namelist ::= Name {‘,’ Name}

	explist ::= exp {‘,’ exp}

	exp ::=  nil | false | true | Numeral | LiteralString | ‘...’ | functiondef | 
		 prefixexp | tableconstructor | exp binop exp | unop exp 

	prefixexp ::= var | functioncall | ‘(’ exp ‘)’

	functioncall ::=  prefixexp args | prefixexp ‘:’ Name args 

	args ::=  ‘(’ [explist] ‘)’ | tableconstructor | LiteralString 

	functiondef ::= function funcbody

	funcbody ::= ‘(’ [parlist] ‘)’ block end

	parlist ::= namelist [‘,’ ‘...’] | ‘...’

	tableconstructor ::= ‘{’ [fieldlist] ‘}’

	fieldlist ::= field {fieldsep field} [fieldsep]

	field ::= ‘[’ exp ‘]’ ‘=’ exp | Name ‘=’ exp | exp

	fieldsep ::= ‘,’ | ‘;’

	binop ::=  ‘+’ | ‘-’ | ‘*’ | ‘/’ | ‘//’ | ‘^’ | ‘%’ | 
		 ‘&’ | ‘~’ | ‘|’ | ‘>>’ | ‘<<’ | ‘..’ | 
		 ‘<’ | ‘<=’ | ‘>’ | ‘>=’ | ‘==’ | ‘~=’ | 
		 and | or

	unop ::= ‘-’ | not | ‘#’ | ‘~


æœ€åŽæ›´æ–°æ—¶é—´ï¼š 2015å¹´1月18æ—¥19:54