﻿<?xml version="1.0" encoding="utf-8" standalone="yes"?><rss version="2.0" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:trackback="http://madskills.com/public/xml/rss/module/trackback/" xmlns:wfw="http://wellformedweb.org/CommentAPI/" xmlns:slash="http://purl.org/rss/1.0/modules/slash/"><channel><title>C++博客-清源游民的网络笔记本-随笔分类-Lua</title><link>http://www.cppblog.com/yuanyajie/category/3942.html</link><description>记录所思所想，收藏所见所闻�?
</description><language>zh-cn</language><lastBuildDate>Fri, 08 May 2009 08:50:43 GMT</lastBuildDate><pubDate>Fri, 08 May 2009 08:50:43 GMT</pubDate><ttl>60</ttl><item><title>试用新版本luabind</title><link>http://www.cppblog.com/yuanyajie/archive/2009/05/07/82117.html</link><dc:creator>清源游民</dc:creator><author>清源游民</author><pubDate>Wed, 06 May 2009 16:46:00 GMT</pubDate><guid>http://www.cppblog.com/yuanyajie/archive/2009/05/07/82117.html</guid><wfw:comment>http://www.cppblog.com/yuanyajie/comments/82117.html</wfw:comment><comments>http://www.cppblog.com/yuanyajie/archive/2009/05/07/82117.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/yuanyajie/comments/commentRss/82117.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/yuanyajie/services/trackbacks/82117.html</trackback:ping><description><![CDATA[环境xp sp3 , vs2008 sp1, luabind 0.8.1,lua 5.1.4 , boost 1_36_0<br>先把lua, luabind 编成静态库，（下图只是debug,release类似)：<br><br><img src="http://www.cppblog.com/images/cppblog_com/yuanyajie/lua_bind_lib.png" border=0><br>做完之后整理，lua, luabind 以sdk 形式组织好，我是这样组织:<br>\luabind_build\sdk\luabind\include<br>\luabind_build\sdk\luabind\msvc-9.0-sp1\lib<br>\luabind_build\sdk\lua\include<br>\luabind_build\sdk\lua\msvc-9.0-sp1\lib<br>这样，把sdk中的东东保存一份，方便以后使用。写一个MFC小程序测试<br><img src="http://www.cppblog.com/images/cppblog_com/yuanyajie/mfc_lua.png" border=0><br><br>
<div style="BORDER-RIGHT: #cccccc 1px solid; PADDING-RIGHT: 5px; BORDER-TOP: #cccccc 1px solid; PADDING-LEFT: 4px; FONT-SIZE: 13px; PADDING-BOTTOM: 4px; BORDER-LEFT: #cccccc 1px solid; WIDTH: 98%; WORD-BREAK: break-all; PADDING-TOP: 4px; BORDER-BOTTOM: #cccccc 1px solid; BACKGROUND-COLOR: #eeeeee"><span style="COLOR: #008080">&nbsp;1</span>&nbsp;<span style="COLOR: #008000">//</span><span style="COLOR: #008000">关键代码<br></span><span style="COLOR: #008080">&nbsp;2</span>&nbsp;<span style="COLOR: #008000"></span><span style="COLOR: #008000">//</span><span style="COLOR: #008000">mfc&nbsp;class&nbsp;function</span><span style="COLOR: #008000"><br></span><span style="COLOR: #008080">&nbsp;3</span>&nbsp;<span style="COLOR: #008000"></span><span style="COLOR: #0000ff">void</span><span style="COLOR: #000000">&nbsp;CMFC_LuaDlg::SetEditText(</span><span style="COLOR: #0000ff">const</span><span style="COLOR: #000000">&nbsp;</span><span style="COLOR: #0000ff">char</span><span style="COLOR: #000000">*</span><span style="COLOR: #000000">&nbsp;text)<br></span><span style="COLOR: #008080">&nbsp;4</span>&nbsp;<span style="COLOR: #000000">{<br></span><span style="COLOR: #008080">&nbsp;5</span>&nbsp;<span style="COLOR: #000000">&nbsp;&nbsp;&nbsp;&nbsp;Edit_1.SetWindowText(text);<br></span><span style="COLOR: #008080">&nbsp;6</span>&nbsp;<span style="COLOR: #000000">&nbsp;&nbsp;&nbsp;&nbsp;UpdateData(FALSE);<br></span><span style="COLOR: #008080">&nbsp;7</span>&nbsp;<span style="COLOR: #000000">}<br></span><span style="COLOR: #008080">&nbsp;8</span>&nbsp;<span style="COLOR: #000000"></span><span style="COLOR: #008000">//</span><span style="COLOR: #008000">register</span><span style="COLOR: #008000"><br></span><span style="COLOR: #008080">&nbsp;9</span>&nbsp;<span style="COLOR: #008000"></span><span style="COLOR: #000000">luabind::module(L)<br></span><span style="COLOR: #008080">10</span>&nbsp;<span style="COLOR: #000000">&nbsp;&nbsp;&nbsp;&nbsp;[<br></span><span style="COLOR: #008080">11</span>&nbsp;<span style="COLOR: #000000">&nbsp;&nbsp;&nbsp;&nbsp;luabind::class_</span><span style="COLOR: #000000">&lt;</span><span style="COLOR: #000000">CMFC_LuaDlg</span><span style="COLOR: #000000">&gt;</span><span style="COLOR: #000000">(</span><span style="COLOR: #000000">"</span><span style="COLOR: #000000">mfc_dlg</span><span style="COLOR: #000000">"</span><span style="COLOR: #000000">)<br></span><span style="COLOR: #008080">12</span>&nbsp;<span style="COLOR: #000000">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;.def</span><span style="COLOR: #000000">"</span><span style="COLOR: #000000">set_text</span><span style="COLOR: #000000">"</span><span style="COLOR: #000000">,</span><span style="COLOR: #000000">&amp;</span><span style="COLOR: #000000">CMFC_LuaDlg::SetEditText)<br></span><span style="COLOR: #008080">13</span>&nbsp;<span style="COLOR: #000000">&nbsp;&nbsp;&nbsp;&nbsp;];<br></span><span style="COLOR: #008080">14</span>&nbsp;<span style="COLOR: #000000"></span><span style="COLOR: #008000">//</span><span style="COLOR: #008000">load&nbsp;lua&nbsp;file</span><span style="COLOR: #008000"><br></span><span style="COLOR: #008080">15</span>&nbsp;<span style="COLOR: #008000"></span><span style="COLOR: #0000ff">if</span><span style="COLOR: #000000">&nbsp;(</span><span style="COLOR: #000000">0</span><span style="COLOR: #000000">==</span><span style="COLOR: #000000">luaL_dofile(L,filepath))<br></span><span style="COLOR: #008080">16</span>&nbsp;<span style="COLOR: #000000">&nbsp;&nbsp;&nbsp;&nbsp;{<br></span><span style="COLOR: #008080">17</span>&nbsp;<span style="COLOR: #000000">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;ret</span><span style="COLOR: #000000">=</span><span style="COLOR: #0000ff">true</span><span style="COLOR: #000000">;<br></span><span style="COLOR: #008080">18</span>&nbsp;<span style="COLOR: #000000">&nbsp;&nbsp;&nbsp;&nbsp;}<br></span><span style="COLOR: #008080">19</span>&nbsp;<span style="COLOR: #000000"></span><span style="COLOR: #008000">//</span><span style="COLOR: #008000">run&nbsp;lua&nbsp;function</span><span style="COLOR: #008000"><br></span><span style="COLOR: #008080">20</span>&nbsp;<span style="COLOR: #008000"></span><span style="COLOR: #000000">&nbsp;luabind::call_function</span><span style="COLOR: #000000">&lt;</span><span style="COLOR: #0000ff">void</span><span style="COLOR: #000000">&gt;</span><span style="COLOR: #000000">(L,</span><span style="COLOR: #000000">"</span><span style="COLOR: #000000">update_text</span><span style="COLOR: #000000">"</span><span style="COLOR: #000000">,dlg);<br></span><span style="COLOR: #008080">21</span>&nbsp;<span style="COLOR: #000000"></span></div>
脚本内容:<br>
<div style="BORDER-RIGHT: #cccccc 1px solid; PADDING-RIGHT: 5px; BORDER-TOP: #cccccc 1px solid; PADDING-LEFT: 4px; FONT-SIZE: 13px; PADDING-BOTTOM: 4px; BORDER-LEFT: #cccccc 1px solid; WIDTH: 98%; WORD-BREAK: break-all; PADDING-TOP: 4px; BORDER-BOTTOM: #cccccc 1px solid; BACKGROUND-COLOR: #eeeeee"><span style="COLOR: #008080">1</span>&nbsp;<span style="COLOR: #000000">function&nbsp;update_text(dlg)<br></span><span style="COLOR: #008080">2</span>&nbsp;<span style="COLOR: #000000">&nbsp;&nbsp;&nbsp;dlg:set_text(</span><span style="COLOR: #000000">"</span><span style="COLOR: #000000">你好，欢迎来到lua&nbsp;脚本世界</span><span style="COLOR: #000000">"</span><span style="COLOR: #000000">)<br></span><span style="COLOR: #008080">3</span>&nbsp;<span style="COLOR: #000000">end</span></div>
运行结果：<br><img src="http://www.cppblog.com/images/cppblog_com/yuanyajie/mfc_lua_ret.png" border=0><br><br>
<img src ="http://www.cppblog.com/yuanyajie/aggbug/82117.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/yuanyajie/" target="_blank">清源游民</a> 2009-05-07 00:46 <a href="http://www.cppblog.com/yuanyajie/archive/2009/05/07/82117.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>lua 与 python</title><link>http://www.cppblog.com/yuanyajie/archive/2009/04/28/81354.html</link><dc:creator>清源游民</dc:creator><author>清源游民</author><pubDate>Tue, 28 Apr 2009 13:10:00 GMT</pubDate><guid>http://www.cppblog.com/yuanyajie/archive/2009/04/28/81354.html</guid><wfw:comment>http://www.cppblog.com/yuanyajie/comments/81354.html</wfw:comment><comments>http://www.cppblog.com/yuanyajie/archive/2009/04/28/81354.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/yuanyajie/comments/commentRss/81354.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/yuanyajie/services/trackbacks/81354.html</trackback:ping><description><![CDATA[<p>也许因为都是脚本的缘故吧，越来越觉得lua和python 有某种的类似，感觉它们的关系就像c 和c++一样，<br>当然lua 是c, python 是c++,就连luabind 和&nbsp;&nbsp;boost.python 都差不多，不过最后一点不奇怪，luabind 是从boost.python获得了许多灵感.</p>
<img src ="http://www.cppblog.com/yuanyajie/aggbug/81354.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/yuanyajie/" target="_blank">清源游民</a> 2009-04-28 21:10 <a href="http://www.cppblog.com/yuanyajie/archive/2009/04/28/81354.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>用ConText 搭建简单的lua 开发环境</title><link>http://www.cppblog.com/yuanyajie/archive/2009/04/28/81353.html</link><dc:creator>清源游民</dc:creator><author>清源游民</author><pubDate>Tue, 28 Apr 2009 12:54:00 GMT</pubDate><guid>http://www.cppblog.com/yuanyajie/archive/2009/04/28/81353.html</guid><wfw:comment>http://www.cppblog.com/yuanyajie/comments/81353.html</wfw:comment><comments>http://www.cppblog.com/yuanyajie/archive/2009/04/28/81353.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/yuanyajie/comments/commentRss/81353.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/yuanyajie/services/trackbacks/81353.html</trackback:ping><description><![CDATA[其实很简单，用一个文本编辑器+加lua解释程序，关键就是希望编辑器可以支持lua语法加亮等方便编辑，这样的编辑器太多了，这里选用ConText,然后在编辑器定义某种方式（这里是快捷键）来执行编辑的文件，可以看到解释器的输出，是否出错或是正错的输出。就是这些最简单的功能，Context设置起来也很方便,看看下图就全明白了。<img height=768 alt="" src="http://www.cppblog.com/images/cppblog_com/yuanyajie/context_lua.png" width=1024 border=0>
<img src ="http://www.cppblog.com/yuanyajie/aggbug/81353.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/yuanyajie/" target="_blank">清源游民</a> 2009-04-28 20:54 <a href="http://www.cppblog.com/yuanyajie/archive/2009/04/28/81353.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>(转) Lua 中的范型for</title><link>http://www.cppblog.com/yuanyajie/archive/2007/05/07/23587.html</link><dc:creator>清源游民</dc:creator><author>清源游民</author><pubDate>Mon, 07 May 2007 15:27:00 GMT</pubDate><guid>http://www.cppblog.com/yuanyajie/archive/2007/05/07/23587.html</guid><wfw:comment>http://www.cppblog.com/yuanyajie/comments/23587.html</wfw:comment><comments>http://www.cppblog.com/yuanyajie/archive/2007/05/07/23587.html#Feedback</comments><slash:comments>1</slash:comments><wfw:commentRss>http://www.cppblog.com/yuanyajie/comments/commentRss/23587.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/yuanyajie/services/trackbacks/23587.html</trackback:ping><description><![CDATA[<font face="Courier New" size=4>Lua有一种很自然的循环方式，即Generic for。它的格式是这样的:</font>
<p><font face="Courier New" color=#a52a2a size=4>for namelist in iterator do<br>&nbsp;&nbsp; block<br>end</font></p>
<p><font face="Courier New" size=4>其中iterator是一个迭代器函数，它可以有一个或多个返回值，namelist是逗号分隔的循环变量名列表，用来接收每次调用迭代器函数得到的返回值。这段程序的语义与下面形式的代码相同:</font></p>
<p><font face="Courier New" color=#a52a2a size=4>while true do<br>&nbsp;&nbsp; local namelist = iterator()<br>&nbsp;&nbsp; if nil == first(namelist) then break end<br>&nbsp;&nbsp; block<br>end</font></p>
<p><font face="Courier New" size=4>first(namelist)表示namelist的第一个变量名。</font></p>
<p><font face="Courier New" size=4>&nbsp;&nbsp;&nbsp; Lua已经提供了若干个常用的迭代器生成函数，最常见的就是ipairs和pairs。ipairs(t)以一个table作为参数，生成一个依次返回(1,t[1])、(2,t[2])、(3,t[3])......的迭代器。下面这段代码</font></p>
<p><font face="Courier New" color=#a52a2a size=4>t = {"Monday","Tuesday", "Wednesday","Thursday", "Friday","Saturday","Sunday"}</font></p>
<p><font face="Courier New" color=#a52a2a size=4>for i,v in ipairs(t) do<br>&nbsp;&nbsp; print(i,v)<br>end</font></p>
<p><font face="Courier New" size=4>将会打印出</font></p>
<p><font face="Courier New" size=4>1&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Monday<br>2&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Tuesday<br>3&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Wednesday<br>4&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Thursday<br>5&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Friday<br>6&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Saturday<br>7&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Sunday</font></p>
<p><font face="Courier New" size=4>。pairs同样用一个table作为参数，它生成的迭代器依次返回该表中所有的key和value。</font></p>
<p><font face="Courier New" size=4>&nbsp;&nbsp;&nbsp; Generic for搭配ipairs和pairs用起来相当方便，但是它们却有一个很难察觉的缺陷。看看这段代码:</font></p>
<p><font color=#a52a2a><font face="Courier New" size=4>for i,v in ipairs(t) do<br>&nbsp; print(i,v)<br>&nbsp; </font><font size=4><font face="Courier New"><font color=#006400>-- some code changes i<br></font>&nbsp; i = 0<br>end<br></font></font></font></p>
<p><font face="Courier New" size=4>许多人(包括我)都猜不出它竟然会不停地疯狂打印</font></p>
<p><font face="Courier New" size=4>1&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Monday</font></p>
<p><font face="Courier New" size=4>，如果用pairs替代ipairs也不会好到哪里去: 在打印出一行数据后便抛出个 invalid key for `next' 错误。</font></p>
<p><font face="Courier New" size=4>&nbsp;&nbsp;&nbsp; 由此可知，使用了ipairs和pairs的Generic for在语义与上文while true ... end形式的代码并不完全相同，它们生成的迭代器需要使用循环变量，而如果循环体改变了循环变量值的话，那么迭代器就很可能会象在本例中那样找不着北了。因此，《Programming in Lua》的4.3.5中便有这么一段谆谆告诫: &#8220;The generic loop shares two properties with the numeric loop: The loop variables are local to the loop body and <font color=#ff0000>you</font> <font color=#ff0000>should never assign any value to the loop variables</font>. "。</font></p>
<p><font face="Courier New" size=4>&nbsp;&nbsp;&nbsp; ipairs和pairs的这个缺陷是由于它们要用当前循环变量的值来作为下一次迭代的起点，那么这是不是必需的呢？当然不是，我们完全可以通过closure来实现一个更安全的ipairs :</font></p>
<p><font face="Courier New" color=#a52a2a size=4>function myipairs (t)<br>&nbsp;&nbsp; local i = 0<br>&nbsp;&nbsp; local n = table.getn(t)<br>&nbsp;&nbsp; return function ()<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; i = i + 1<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if i &lt;= n then return i,t[i] end<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; end<br>end</font></p>
<p><font face="Courier New" color=#a52a2a size=4>t = {"Monday","Tuesday", "Wednesday","Thursday", "Friday","Saturday","Sunday"}</font></p>
<p><font face="Courier New" color=#a52a2a size=4>for i,v in myipairs(t) do<br>&nbsp; print(i,v)<br>&nbsp; <font color=#006400>-- some code changes i</font><br>&nbsp; i = 0<br>end</font></p>
<p><font face="Courier New" size=4>&nbsp;&nbsp;&nbsp; 试试上面这段代码，怎么样？是不是工作得很好？为什么它不会发疯？其实很简单，myipairs生成的迭代器(一个closure)把需要用到的迭代信息保存到它的upvalue(i和n)中，这样即使循环体更改了循环变量也不会影响到迭代状态。感谢closure，我们终于可以放心大胆地粗心一点了！^_^<br></font></p>
<br><br>
<p id=TBPingURL>Trackback: http://tb.blog.csdn.net/TrackBack.aspx?PostId=564518</p>
<img src ="http://www.cppblog.com/yuanyajie/aggbug/23587.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/yuanyajie/" target="_blank">清源游民</a> 2007-05-07 23:27 <a href="http://www.cppblog.com/yuanyajie/archive/2007/05/07/23587.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>让UltraEdit 支持Lua的语法高亮显示</title><link>http://www.cppblog.com/yuanyajie/archive/2007/04/06/21396.html</link><dc:creator>清源游民</dc:creator><author>清源游民</author><pubDate>Fri, 06 Apr 2007 05:57:00 GMT</pubDate><guid>http://www.cppblog.com/yuanyajie/archive/2007/04/06/21396.html</guid><wfw:comment>http://www.cppblog.com/yuanyajie/comments/21396.html</wfw:comment><comments>http://www.cppblog.com/yuanyajie/archive/2007/04/06/21396.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/yuanyajie/comments/commentRss/21396.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/yuanyajie/services/trackbacks/21396.html</trackback:ping><description><![CDATA[&nbsp;&nbsp;&nbsp;&nbsp; 摘要: &nbsp;&nbsp;<a href='http://www.cppblog.com/yuanyajie/archive/2007/04/06/21396.html'>阅读全文</a><img src ="http://www.cppblog.com/yuanyajie/aggbug/21396.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/yuanyajie/" target="_blank">清源游民</a> 2007-04-06 13:57 <a href="http://www.cppblog.com/yuanyajie/archive/2007/04/06/21396.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>学习lua中的闭包</title><link>http://www.cppblog.com/yuanyajie/archive/2007/04/02/21128.html</link><dc:creator>清源游民</dc:creator><author>清源游民</author><pubDate>Mon, 02 Apr 2007 15:21:00 GMT</pubDate><guid>http://www.cppblog.com/yuanyajie/archive/2007/04/02/21128.html</guid><wfw:comment>http://www.cppblog.com/yuanyajie/comments/21128.html</wfw:comment><comments>http://www.cppblog.com/yuanyajie/archive/2007/04/02/21128.html#Feedback</comments><slash:comments>5</slash:comments><wfw:commentRss>http://www.cppblog.com/yuanyajie/comments/commentRss/21128.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/yuanyajie/services/trackbacks/21128.html</trackback:ping><description><![CDATA[<p>Lua中的函数是一阶类型值(first-class value)，定义函数就象创建普通类型值一样(只不过函数类型值的数据主要是一条条指令而已)，所以在函数体中仍然可以定义函数。假设函数f2定义在函数f1中，那么就称f2为f1的内嵌(inner)函数，f1为f2的外包(enclosing)函数，外包和内嵌都具有传递性，即f2的内嵌必然是f1的内嵌，而f1的外包也一定是f2的外包。内嵌函数可以访问外包函数已经创建的所有局部变量，这种特性便是所谓的词法定界(lexical scoping)，而这些局部变量则称为该内嵌函数的外部局部变量(external local variable)或者upvalue(这个词多少会让人产生误解，因为upvalue实际指的是变量而不是值)。试看如下代码： <br></p>
<p><font face="Courier New" color=#a52a2a size=4>function f1(n)<br>&nbsp;&nbsp; <font color=#006400>-- 函数参数也是局部变量</font></font></p>
<p><font face="Courier New" color=#a52a2a size=4>&nbsp;&nbsp; local function f2()<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; print(n) <font color=#006400>-- 引用外包函数的局部变量</font><br>&nbsp;&nbsp; end<br>&nbsp;&nbsp; return f2<br>end</font></p>
<p><font face="Courier New" color=#a52a2a size=4>g1 = f1(1979)<br>g1() <font color=#006400>-- 打印出1979</font><br>g2 = f1(500)<br>g2() <font color=#006400>-- 打印出500</font></font></p>
<p><br>当执行完g1 = f1(1979)后，局部变量n的生命本该结束，但因为它已经成了内嵌函数f2(它又被赋给了变量g1)的upvalue，所以它仍然能以某种形式继续&#8220;存活&#8221;下来，从而令g1()打印出正确的值。</p>
<p>&nbsp;&nbsp;&nbsp; 可为什么g2与g1的函数体一样(都是f1的内嵌函数f2的函数体)，但打印值不同？这就涉及到一个相当重要的概念——闭包(closure)。事实上，Lua编译一个函数时，会为它生成一个原型(prototype)，其中包含了函数体对应的虚拟机指令、函数用到的常量值(数，文本字符串等等)和一些调试信息。在运行时，每当Lua执行一个形如function...end 这样的表达式时，它就会创建一个新的数据对象，其中包含了相应函数原型的引用、环境(environment，用来查找全局变量的表)的引用以及一个由所有upvalue引用组成的数组，而这个数据对象就称为闭包。由此可见，函数是编译期概念，是静态的，而闭包是运行期概念，是动态的。g1和g2的值严格来说不是函数而是闭包，并且是两个不相同的闭包，而每个闭包可以保有自己的upvalue值，所以g1和g2打印出的结果当然就不一样了。虽然闭包和函数是本质不同的概念，但为了方便，且在不引起混淆的情况下，我们对它们不做区分。</p>
<p>&nbsp;&nbsp;&nbsp; 使用upvalue很方便，但它们的语义也很微妙，需要引起注意。比如将f1函数改成：<br></p>
<p><font face="Courier New" color=#a52a2a size=4>function f1(n)<br>&nbsp;&nbsp; local function f2()<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; print(n)<br>&nbsp;&nbsp; end<br>&nbsp;&nbsp; n = n + 10<br>&nbsp;&nbsp; return f2<br>end</font></p>
<p><font face="Courier New" color=#a52a2a size=4>g1 = f1(1979)<br>g1() <font color=#006400>-- 打印出1989</font></font></p>
<p><br>内嵌函数定义在n = n + 10这条语句之前，可为什么g1()打印出的却是1989？upvalue实际是局部变量，而局部变量是保存在函数堆栈框架上(stack frame)的，所以只要upvalue还没有离开自己的作用域，它就一直生存在函数堆栈上。这种情况下，闭包将通过指向堆栈上的upvalue的引用来访问它们，一旦upvalue即将离开自己的作用域(这也意味着它马上要从堆栈中消失)，闭包就会为它分配空间并保存当前的值，以后便可通过指向新分配空间的引用来访问该upvalue。当执行到f1(1979)的n = n + 10时，闭包已经创建了，但是n并没有离开作用域，所以闭包仍然引用堆栈上的n，当return f2完成时，n即将结束生命，此时闭包便将n(已经是1989了)复制到自己管理的空间中以便将来访问。弄清楚了内部的秘密后，运行结果就不难解释了。</p>
<p>upvalue还可以为闭包之间提供一种数据共享的机制。试看下例：<br></p>
<p><font face="Courier New" color=#a52a2a size=4>function Create(n)<br>&nbsp;&nbsp; local function foo1()<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; print(n)<br>&nbsp;&nbsp; end</font></p>
<p><font face="Courier New" color=#a52a2a size=4>&nbsp;&nbsp; local function foo2()<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; n = n + 10<br>&nbsp;&nbsp; end</font></p>
<p><font face="Courier New" color=#a52a2a size=4>&nbsp;&nbsp; return foo1,foo2<br>end</font></p>
<p><font face="Courier New" color=#a52a2a size=4>f1,f2 = Create(1979)<br>f1() <font color=#006400>-- 打印1979</font><br>f2()<br>f1() <font color=#006400>-- 打印1989</font><br>f2()<br>f1() <font color=#006400>-- 打印1999</font></font></p>
<p><br>f1,f2这两个闭包的原型分别是Create中的内嵌函数foo1和foo2，而foo1和foo2引用的upvalue是同一个，即Create的局部变量n。前面已说过，执行完Create调用后，闭包会把堆栈上n的值复制出来，那么是否f1和f2就分别拥有一个n的拷贝呢？其实不然，当Lua发现两个闭包的upvalue指向的是当前堆栈上的相同变量时，会聪明地只生成一个拷贝，然后让这两个闭包共享该拷贝，这样任一个闭包对该upvalue进行修改都会被另一个探知。上述例子很清楚地说明了这点：每次调用f2都将upvalue的值增加了10，随后f1将更新后的值打印出来。upvalue的这种语义很有价值，它使得闭包之间可以不依赖全局变量进行通讯，从而使代码的可靠性大大提高。</p>
<p>&nbsp;&nbsp;&nbsp; 闭包在创建之时其upvalue就已经不在堆栈上的情况也有可能发生，这是因为内嵌函数可以引用更外层外包函数的局部变量：<br></p>
<p><font face="Courier New" color=#a52a2a size=4>function Test(n)<br>&nbsp;&nbsp; local function foo()<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; local function inner1()<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; print(n)<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; end<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; local function inner2()<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; n = n + 10<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; end<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; return inner1,inner2<br>&nbsp;&nbsp; end<br>&nbsp;&nbsp; return foo<br>end</font></p>
<p><font face="Courier New" color=#a52a2a size=4>t = Test(1979)<br>f1,f2 = t()<br>f1()&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <font color=#006400>-- 打印1979</font><br>f2()<br>f1()&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <font color=#006400>-- 打印1989</font><br>g1,g2 = t()<br>g1()&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <font color=#006400>-- 打印1989</font><br>g2()<br>g1()&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <font color=#006400>-- 打印1999</font><br>f1()&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <font color=#006400>-- 打印1999</font></font></p>
<p><br>执行完t = Test(1979)后，Test的局部变量n就&#8220;死&#8221;了，所以当f1,f2这两个闭包被创建时堆栈上根本找不到n的踪影，这叫它们如何取得n的值呢？呵呵，不要忘了Test函数的n不仅仅是inner1和inner2的upvalue，同时它也是foo的upvalue。t = Test(1979)之后，t这个闭包一定已经把n妥善保存好了，之后f1、f2如果在当前堆栈上找不到n就会自动到它们的外包闭包(姑且这么叫)的upvalue引用数组中去找，并把找到的引用值拷贝到自己的upvalue引用数组中。仔细观察上述代码，可以判定g1和g2与f1和f2共享同一个upvalue。这是为什么呢？其实，g1和g2与f1和f2都是同一个闭包(t)创建的，所以它们引用的upvalue(n)实际也是同一个变量，而刚才描述的搜索机制则保证了最后它们的upvalue引用都会指向同一个地方。</p>
<p>&nbsp;&nbsp; <br></p>
<img src ="http://www.cppblog.com/yuanyajie/aggbug/21128.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/yuanyajie/" target="_blank">清源游民</a> 2007-04-02 23:21 <a href="http://www.cppblog.com/yuanyajie/archive/2007/04/02/21128.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item></channel></rss>