2017-05-20 37 views
3

这可能是一个愚蠢的问题,但是,我不知道发生了什么。Lua忽略范围变量

我有一个简单的脚本获取谷歌时间,我需要将它设置为time全局变量。因此,在receive事件中,我打印了取回的时间并且它正常工作。

问题是变量time在事件外被调用时总是空的。下面是代码:

-- test.lua 
time = "" 

function getTime() 
    conn = net.createConnection(net.TCP, 0) 

    conn:connect(80,'google.com') 
    conn:on("connection", function(conn, payload) 
    conn:send("HEAD/HTTP/1.1\r\n".. 
      "Host: google.com\r\n".. 
      "Accept: */*\r\n".. 
      "User-Agent: Mozilla/4.0 (compatible; esp8266 Lua;)".. 
      "\r\n\r\n" 
    ) 
    end) 

    conn:on("receive", function(conn, payload) 
    conn:close() 
    time = string.sub(payload,string.find(payload,"Date: ") 
     +6,string.find(payload,"Date: ")+35) 
    end) 
    print("testing: " .. time) -- WORKS! 
end 

getTime() 
print("variable: ".. time) 

这里是我如何调用该函数(使用nodemcu-上传终端):

➜ test nu terminal 
--- Miniterm on /dev/cu.wchusbserial1410 115200,8,N,1 --- 
--- Quit: Ctrl+] | Menu: Ctrl+T | Help: Ctrl+T followed by Ctrl+H --- 

> dofile('lib/test.lua') 
variable: 
> testing: Sat, 20 May 2017 01:37:35 GMT 

任何帮助将非常感激! 谢谢

+0

当心!这会造成内存泄漏,因为您在'connection'和'receive'回调中重新使用'conn'变量。请参阅http://stackoverflow.com/a/37379426/131929。 –

+0

@MarcelStör..在事件结束时设置为'nil'可以解决这个问题吗? – hugalves

回答

1

NodeMCU编程模型与Node.js类似,只在Lua中。它是异步的和事件驱动的。因此,许多函数都具有回调函数的参数。

来源:https://github.com/nodemcu/nodemcu-firmware/#programming-model

这意味着,其接受回调函数作为参数是功能非阻塞。它返回意味着你不能逐行阅读一段代码,并期望它按照该顺序执行。

所以,在你原来的程序事件的顺序大致是这样的:

  • getTime被触发但不会阻止
  • print("variable: ".. time)被执行。 time在这一点上仍然是空的。
  • 建立了与google.com的连接。
  • HEAD请求已发送至google.com。
  • 响应是接收和接收事件处理程序(即匿名回调函数)踢入。
  • time已填充。

我看到两个明显的修复,一个使用全局变量time,另一个使用不变。两者都基于传递回调函数作为参数模式。

请注意,你总是应该(在你的情况conn:on)设置你的事件侦听器这些事件被触发(conn:connect),以避免错过一些事件。您的代码

conn:connect(80,'google.com') 
conn:on("connection"... 

只能因为conn:connect是无阻塞,因为它需要一些时间,直到建立连接。在发生这种情况时,连接事件处理程序已被注册。

保持全局变量

time = "" 

function getTime(cb) 
    conn = net.createConnection(net.TCP, 0) 

    conn:on("connection", function(socket, payload) 
    socket:send("HEAD/HTTP/1.1\r\n" .. 
      "Host: google.com\r\n" .. 
      "Accept: */*\r\n" .. 
      "User-Agent: Mozilla/4.0 (compatible; esp8266 Lua;)" .. 
      "\r\n\r\n") 
    end) 

    conn:on("receive", function(socket, payload) 
    socket:close() 
    time = string.sub(payload, string.find(payload, "Date: ") 
      + 6, string.find(payload, "Date: ") + 35) 
    print("time inside on-receive: " .. time) 
    cb() 
    end) 

    conn:connect(80, 'google.com') 
end 

function do_something_with_time() 
    print("time inside callback: " .. time) 
end 

getTime(do_something_with_time) 

没有全局变量

function getTime(cb) 
    conn = net.createConnection(net.TCP, 0) 

    conn:on("connection", function(socket, payload) 
    socket:send("HEAD/HTTP/1.1\r\n" .. 
      "Host: google.com\r\n" .. 
      "Accept: */*\r\n" .. 
      "User-Agent: Mozilla/4.0 (compatible; esp8266 Lua;)" .. 
      "\r\n\r\n") 
    end) 

    conn:on("receive", function(socket, payload) 
    socket:close() 
    local time = string.sub(payload, string.find(payload, "Date: ") 
      + 6, string.find(payload, "Date: ") + 35) 
    print("time inside on-receive: " .. time) 
    cb(time) 
    end) 

    conn:connect(80, 'google.com') 
end 

function do_something_with_time(time) 
    print("time inside callback: " .. time) 
end 

getTime(do_something_with_time) 
+0

DAAAAMN !!你摇滚!我完全理解!非常感谢你!! – hugalves

2

它看起来像范围很好。查看输出打印的订单。

conn:connectcon:on采取功能,因为它们是异步的。 getTime()只是在被调用之前返回。

+0

我不知道这个..你有什么建议来处理这个吗?睡觉? – hugalves

+1

@hugalves最简单的方法是将函数传递给getTime并调用它,而不是设置时间。该功能可以设置时间和打印。但是你的程序可能比这更复杂。 –

+1

我的建议是学习基于事件的编程。使用信号和事件会​​使您的代码/设备响应更快。阻塞会导致不好的事情发生。阅读常见问题,它涵盖了很多:https://nodemcu.readthedocs.io/en/master/en/lua-developer-faq/ –