GVKun编程网logo

Lua的upvalue和闭包(lua闭包的优缺点)

17

想了解Lua的upvalue和闭包的新动态吗?本文将为您提供详细的信息,我们还将为您解答关于lua闭包的优缺点的相关问题,此外,我们还将为您介绍关于$watch中的oldvalue和newValue、

想了解Lua的upvalue和闭包的新动态吗?本文将为您提供详细的信息,我们还将为您解答关于lua闭包的优缺点的相关问题,此外,我们还将为您介绍关于$watch中的oldvalue和newValue、5.1之前, 全局变量存储在_G这个table中, 这样的操作:5.3 lua_setupvalue、Citizen:/scripting/lua/scheduler.lua:61: 尝试调用一个 nil 值 (upvalue 'fn')、Lua 5.0实现 4 函数和闭包的新知识。

本文目录一览:

Lua的upvalue和闭包(lua闭包的优缺点)

Lua的upvalue和闭包(lua闭包的优缺点)

Lua函数可以被当成参数传递,也可以被当成结果返回,在函数体中仍然可以定义内嵌函数。lua闭包是Lua函数生成的数据对象。每个闭包可以有一个upvalue值,或者多个闭包共享一个upvalue数值。

1、upvalue

如果函数f2定义在函数f1中,那么f2为f1的内嵌函数,f1为f2的外包函数,外包和内嵌都具有传递性,即f2的内嵌必然是f1的内嵌,而f1的外包也一定是f2的外包。

内嵌函数可以访问外包函数已经创建的局部变量,而这些局部变量则称为该内嵌函数的外部局部变量(或者upvalue)

代码如下:

function f1(n)
	-- 函数参数也是局部变量
	local function f2()
		print(n) -- 引用外包函数的局部变量
	end
	return f2
end

g1 = f1(1979)
g1() -- 打印出1979
g2 = f1(500)
g2() -- 打印出500

当执行完g1 = f1(1979)后,局部变量n的生命本该结束,但因为它已经成了内嵌函数f2的upvalue,它又被赋给了变量g1,所以它仍然能以某种形式继续“存活”下来,从而令g1()打印出正确的值。

2、闭包

  Lua编译一个函数时,其中包含了函数体对应的虚拟机指令、函数用到的常量值(数,文本字符串等等)和一些调试信息。在运行时,每当Lua执行一个形如function...end 这样的函数时,它就会创建一个新的数据对象,其中包含了相应函数原型的引用、环境(用来查找全局变量的表)的引用以及一个由所有upvalue引用组成的数组,而这个数据对象就称为闭包。由此可见,函数是编译期概念,是静态的,而闭包是运行期概念,是动态的。g1和g2的值严格来说不是函数而是闭包,并且是两个不相同的闭包,而这两个闭包保有各自的upvalue值。
  
使用upvalue代码如下:
function f1(n)
	local function f2()
		print(n)
	end
	n = n + 10
	return f2
end

g1 = f1(1979)
g1() -- 打印出1989

g1()打印出来的是1989,原因是打印的是upvalue的值。

upvalue实际是局部变量,而局部变量是保存在函数堆栈框架上的,所以只要upvalue还没有离开自己的作用域,它就一直生存在函数堆栈上。这种情况下,闭包将通过指向堆栈上的upvalue的引用来访问它们,一旦upvalue即将离开自己的作用域,在从堆栈上消除之前,闭包就会为它分配空间并保存当前的值,以后便可通过指向新分配空间的引用来访问该upvalue。当执行到f1(1979)的n = n + 10时,闭包已经创建了,但是变量n并没有离开作用域,所以闭包仍然引用堆栈上的n,当return f2完成时,n即将结束生命,此时闭包便将变量n(已经是1989了)复制到自己管理的空间中以便将来访问。 

3、upvalue和闭包数据共享

upvalue还可以为闭包之间提供一种数据共享的机制。

(1)单重内嵌函数的闭包 (函数创建的闭包)

一个函数创建的闭包共享一份upvalue。

代码如下:

function Create(n)
	local function foo1()
		print(n)
	end

	local function foo2()
		n = n + 10
	end

	return foo1,foo2
end

f1,f2 = Create(1979)--创建闭包
f1() -- 打印1979
f2()
f1() -- 打印1989
f2()
f1() -- 打印1999
  f1,f2这两个闭包的原型分别是Create中的内嵌函数foo1和foo2,而foo1和foo2引用的upvalue是同一个,即Create的局部变量n。执行完Create调用后,闭包会把堆栈上n的值复制出来,那么是否f1和f2就分别拥有一个n的拷贝呢?其实不然,当Lua发现两个闭包的upvalue指向的是当前堆栈上的相同变量时,会聪明地只生成一个拷贝,然后让这两个闭包共享该拷贝,这样任一个闭包对该upvalue进行修改都会被另一个探知。上述例子很清楚地说明了这点:每次调用f2都将upvalue的值增加了10,随后f1将更新后的值打印出来。upvalue的这种语义很有价值,它使得闭包之间可以不依赖全局变量进行通讯,从而使代码的可靠性大大提高。

(2)多重内嵌函数的闭包 (闭包创建的闭包)

同一闭包创建的其他的闭包共享一份upvalue。

闭包在创建之时其需要的变量就已经不在堆栈上,而是引用更外层外包函数的局部变量(实际上是upvalue)。

function Test(n)
	local function foo()
		local function inner1()
			print(n)
		end
	
		local function inner2()
			n = n + 10
		end
		
		return inner1,inner2
	end
	return foo
end

t = Test(1979)--创建闭包(共享一份upvalue)
f1,f2 = t()--创建闭包
f1()        -- 打印1979
f2()
f1()        -- 打印1989
g1,g2 = t()
g1()        -- 打印1989
g2()
g1()        -- 打印1999
f1()        -- 打印1999

  执行完t = Test(1979)后,Test的局部变量n就结束生命周期了,所以当f1,f2这两个闭包被创建时堆栈上根本找不到变量n。Test函数的局部变量n不仅是foo的upvalue,也是inner1和inner2的upvalue。t = Test(1979)之后,闭包t  已经把n保存为upvalue,之后f1、f2如果在当前堆栈上找不到变量n就会自动到它们的外包闭包(这里是t的)的upvalue引用数组中去找.

  g1和g2与f1和f2共享同一个upvalue。因为g1和g2与f1和f2都是同一个闭包t 创建的,所以它们引用的upvalue  (变量n)实际也是同一个变量,而它们的upvalue引用都会指向同一个地方。

   

$watch中的oldvalue和newValue

$watch中的oldvalue和newValue

vue中提供了$watch的方法来做对象变化的监听,而且在callback中会返回两个对象,分别是oldValue和newValue.
顾名思义,这两个对象就是对象发生变化前后的值。
但是在使用过程中我发现这两个值并不总是预期的。

定义data的值

data: {
    arr: [{
      name: ''笨笨'',
      address: ''上海''
    }, {
      name: ''笨笨熊'',
      address: ''北京''
    }],
    obj: {
      name: ''呆呆'',
      address: ''苏州''
    },
    str: ''哈哈哈''
  }

定义watch

watch: {
    arr: function(newValue, oldValue) {
      console.log(newValue, oldValue)
      console.log(JSON.stringify(oldValue) === JSON.stringify(newValue))
    },
    obj: function(newValue, oldValue) {
      console.log(newValue, oldValue)
      console.log(JSON.stringify(oldValue) === JSON.stringify(newValue))
    },
    str: function(newValue, oldValue) {
      console.log(newValue, oldValue)
      console.log(JSON.stringify(oldValue) === JSON.stringify(newValue))
    },
  }

定义事件触发

methods: {
    test() {
      this.arr.push({
        name: 9
      })
      this.$set(this.obj, ''i'', 0)
      this.str = ''''
    },
    test1() {
      this.arr = [{
        name: ''000''
      }]
      this.obj = {
        name: 999
      }
      this.str = ''123''
    }
  }

测试结果为

对数组进行push操作和对Obj进行$set操作,虽然都可能触发watch事件,但是在callback返回的结果中,oldValue和newValue相同。字符串对象如预期返回

在对数组和Obj统一进行赋值操作时,watch触发并且oldValue和newValue如预期返回

关于watch的其他测试可以参考我之前的文章
vue中正确的使用watch进行监听

测试地址(测试时请打开控制台)
https://zuank.github.io/notes...

5.1之前, 全局变量存储在_G这个table中, 这样的操作:5.3 lua_setupvalue

5.1之前, 全局变量存储在_G这个table中, 这样的操作:5.3 lua_setupvalue

总结

以上是小编为你收集整理的5.1之前, 全局变量存储在_G这个table中, 这样的操作:5.3 lua_setupvalue全部内容。

如果觉得小编网站内容还不错,欢迎将小编网站推荐给好友。

Citizen:/scripting/lua/scheduler.lua:61: 尝试调用一个 nil 值 (upvalue 'fn')

Citizen:/scripting/lua/scheduler.lua:61: 尝试调用一个 nil 值 (upvalue 'fn')

您的代码的屏幕截图显示了对 getBoundaryFunc 的两次调用

runWithBoundaryStart = getBoundaryFunc(Citizen.SubmitBoundaryStart)
runWithBoundaryEnd = getBoundaryFunc(Citizen.SubmitBoundaryEnd)

为了使 fn 变为 nil,必须在不证明第一个参数的情况下调用任何一个函数。

  1. 了解是否有更多对 getBoundaryFunc 的调用
  2. 找出是否使用 nil 而不是预期的函数值作为第一个参数调用其返回值
  3. 解决这个问题

Lua 5.0实现 4 函数和闭包

Lua 5.0实现 4 函数和闭包

总结

以上是小编为你收集整理的Lua 5.0实现 4 函数和闭包全部内容。

如果觉得小编网站内容还不错,欢迎将小编网站推荐给好友。

今天关于Lua的upvalue和闭包lua闭包的优缺点的讲解已经结束,谢谢您的阅读,如果想了解更多关于$watch中的oldvalue和newValue、5.1之前, 全局变量存储在_G这个table中, 这样的操作:5.3 lua_setupvalue、Citizen:/scripting/lua/scheduler.lua:61: 尝试调用一个 nil 值 (upvalue 'fn')、Lua 5.0实现 4 函数和闭包的相关知识,请在本站搜索。

本文标签: