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) -- 运行正常!
end

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

这是如何调用函数的(使用nodemcu-uploader终端):

  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

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

点赞
用户7949696
用户7949696

看起来作用域没问题。查看输出的顺序。

conn:connectcon:on 接受函数,因为它们是异步的。getTime() 在它们被调用之前就已经返回了。

2017-05-20 01:52:58
用户131929
用户131929

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

这意味着接受回调函数作为参数的函数是非阻塞的。这意味着你不能只按照代码中的一行一行地读取它,并期望按照那个顺序执行它。

因此,您原始程序中的事件序列大致如下:

  • 触发getTime但是不阻塞。
  • 执行print("variable: ".. time)。此时time仍为空。
  • 连接到google.com。
  • 发送到google.com的HEAD请求。
  • 接收到响应并调用接收事件处理程序(即匿名回调函数)。
  • time被填充。

我看到两个明显的修复方法,一个是使用全局的time变量,一个是不用。

请注意,您应该始终在这些事件被触发之前设置好您的事件侦听器(conn:on在您的情况下)以避免错过一些事件。您的代码

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

之所以能工作,是因为conn:connect是非阻塞的,并且因为连接建立需要一些时间。在这之前,已经注册了on-connection事件处理程序。

保持全局变量

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)
2017-05-25 11:12:47