[转帖]lua-book-元表

lua,book · 浏览次数 : 0

小编点评

**Lua 元表表现行为** 在 Lua5.1 中,元表 (metatable) 的行为类似于 C++ 语言中的操作符重载,类似 PHP 的魔术方法。 **设置元表的 方法** ```lua setmetatable(table, metatable) ``` **获取元表的 方法** ```lua getmetatable(table) ``` **重载元方法** 元表允许您重载元方法,实现不同的操作。例如,以下代码使用 `__add` 方法来计算两个 Lua 数组的并集: ```lua setmetatable(set1, {\t__add = function(self, another)\t\tlocal res = {}\t\t\tfor k,v in pairs(self) do set[v] = true end -- 防止集合元素重复\t\tfor k,v in pairs(another) do set[v] = true end -- 防止集合元素重复\t\tfor k,v in pairs(set) do table.insert(res, k) end\t\t\t\treturn res\tend}) ``` **元方法的特性** * **__index**:如果元表中存在方法名 `__index`,则该方法会用于表中查找键不存在时转而在元表中查找该键的功能。 * **__newindex**:如果元表中存在方法名 `__newindex`,则该方法会用于在表中查找键不存在时返回元表中该键的值。 * **__call**:如果元表中存在方法名 `__call`,则当调用该方法时会将该方法传递给目标对象。 **其他元方法** 除了 `__index`、`__newindex` 和 `__call` 之外的其他方法,还有一些其他元方法,如 `__add`、`__sub`、`__mul`、`__div`、`__mod`、`__pow` 和 `__unm` 等。

正文

http://me.52fhy.com/lua-book/chapter9.html

 


在Lua5.1语言中,元表 (metatable) 的表现行为类似于 C++ 语言中的操作符重载,类似PHP的魔术方法。Python里也有元类(metaclass)一说。

通过元表,Lua有了更多的扩展特性。Lua的面向对象特性就是基于元表实现的。

Lua 提供了两个十分重要的用来处理元表的方法,如下:

  • setmetatable(table, metatable):此方法用于为一个表设置元表。
  • getmetatable(table):此方法用于获取表的元表对象。

设置元表的方法很简单,如下:

local mytable = {}
local mymetatable = {}
setmetatable(mytable, mymetatable)

上面的代码可以简写成如下的一行代码:

local mytable = setmetatable({}, {})

例如我们可以重载 __add 元方法 (metamethod),实现重载+操作符,来计算两个 Lua 数组的并集:

-- 计算集合的并集实例
set1 = {10,40}
set2 = {10,20,30}

setmetatable(set1, {
	__add = function(self, another)
		local res = {}
		local set = {}
		
		for k,v in pairs(self) do set[v] = true end -- 防止集合元素重复
		for k,v in pairs(another) do set[v] = true end -- 防止集合元素重复
		
		for k,v in pairs(set) do table.insert(res, k) end
		
		return res
	end
})

local set3 = set1 + set2
for k,v in pairs(set3) do print(v) end 

输出:

30
20
10
40

类似的元方法还有:

  • __add +操作
  • __sub -操作 其行为类似于 add 操作
  • __mul *操作 其行为类似于 add 操作
  • __div /操作 其行为类似于 add 操作
  • __mod %操作 其行为类似于 add 操作
  • __pow ^(幂)操作 其行为类似于 add 操作
  • __unm 一元 - 操作
  • __concat ..(字符串连接) 操作
  • __len #操作
  • __eq ==操作 函数 getcomphandler 定义了 Lua 怎样选择一个处理器来作比较操作,仅在两个对象类型相同且有对应操作相同的元方法时才起效
  • __lt <操作
  • __le <=操作

  • __index 取下标操作用于访问 table[key]
  • __newindex 赋值给指定下标 table[key] = value
  • __tostring 转换成字符串
  • __call 当 Lua 调用一个值时调用
  • __mode 用于弱表(week table)
  • __metatable 用于保护metatable不被访问

__index 元方法

该方法实现了在表中查找键不存在时转而在元表中查找该键的功能。有两种写法:

第一种是给 __index 元方法一个函数:

local mytable = setmetatable({}, {
	__index = function(self, key)
		return "__index"
	end
})
print(mytable.key1) -- __index 

另一种方法是给 __index 元方法一个表:

local _M = {
	add = function(x,y) return x+y end,
	mul = function(x,y) return x*y end,
	ver = "1.0",
}
local mytable = setmetatable({}, {
	__index = _M
})
print(mytable.ver) -- 1.0 
print(mytable.add(1,3)) -- 4 

Lua查找一个表元素时的规则,其实就是如下3个步骤:

  1. 在表中查找,如果找到,返回该元素,找不到则继续
  2. 判断该表是否有元表,如果没有元表,返回nil,有元表则继续。
  3. 判断元表有没有__index方法,如果__index方法为nil,则返回nil;如果__index方法是一个表,则重复1、2、3;如果__index方法是一个函数,则返回该函数的返回值。

通过__index这个方法,我们可以实现继承的特性。下节再详细讲述。

__newindex 元方法

如果说__index具有PHP里__get的一些特性,那么__newindex则类似__set

以下实例使用了 rawset 函数来更新表:

mytable = setmetatable({key1 = "value1"}, {
  __newindex = function(self, key, value)
        rawset(self, key, "\""..value.."\"")

  end
})

mytable.key1 = "new value"
mytable.key2 = 4

print(mytable.key1,mytable.key2)

以上实例执行输出结果为:

new value    "4"

__tostring 元方法

如果设置了__tostring 元方法,当直接输出表时会自动调用该方法。示例:

local mytable = setmetatable({ 10, 20, 30 }, {
  __tostring = function(mytable)
    sum = 0
    for k, v in pairs(mytable) do
        sum = sum + v
    end
    return sum
  end
})
print(mytable) -- 60

__call 元方法

__call 元方法的功能类似于 C++ 中的仿函数,使得普通的表也可以被调用。

local mytable = setmetatable({}, {
  __call = function(self, arg)
	local sum = 0
	for _,v in pairs(arg) do
		sum = sum + v
	end
    print(sum)
  end
})
mytable({10,20,30}) -- 60

示例里我们调用自定义的表,并给该表传了参数,最终算出了参数的和。

__metatable 元方法

如果给表设置了 __metatable 元方法的值,getmetatable 将返回这个域的值,而调用 setmetatable将会被禁止,会直接报错。

local mytable = setmetatable({}, {
  __metatable = "no access"
})
print(getmetatable(mytable)) -- no access
setmetatable(mytable, {}) -- 引发编译器报错
lua-book is maintained by 52fhy.This page was generated by GitHub Pages.

与[转帖]lua-book-元表相似的内容:

[转帖]lua-book-元表

http://me.52fhy.com/lua-book/chapter9.html 在Lua5.1语言中,元表 (metatable) 的表现行为类似于 C++ 语言中的操作符重载,类似PHP的魔术方法。Python里也有元类(metaclass)一说。 通过元表,Lua有了更多的扩展特性。Lua

[转帖]lua-book

http://me.52fhy.com/lua-book/chapter2.html 数据类型 [TOC] @date: 2018-3-18 Lua中有8个基本类型分别为:nil、boolean、number、string、table、function、userdata、thread。 函数 typ

[转帖]lua-book-运算符

http://me.52fhy.com/lua-book/chapter3.html Lua支持下列主要的运算符: 算术运算符 关系运算符 逻辑运算符 赋值运算符 还支持..、#特殊运算符。其中赋值运算符仅支持=,不支持C语言的+=、++等运算符。 算术运算符 + 加法 - 减法或者负号 * 乘法

[转帖]lua-book-控制语句

http://me.52fhy.com/lua-book/chapter4.html Lua 语言提供的控制结构有 if-else,while,repeat,for,并提供 break、return 关键字来满足更丰富的需求。不支持switch、continue。 Lua 提供的控制语句部分特征类似

[转帖]lua-book-函数

http://me.52fhy.com/lua-book/chapter5.html 在 Lua 中,函数 也是一种数据类型,函数可以存储在变量中,可以通过参数传递给其他函数,还可以作为其他函数的返回值。 函数定义 函数定义格式: function function_name (arc) -- ar

[转帖]lua-book-模块

http://me.52fhy.com/lua-book/chapter6.html 模块 从Lua5.1开始,Lua添加了对模块和包的支持。 Lua 的模块是由变量、函数等已知元素组成的 table,因此创建一个模块很简单,就是创建一个table,然后把需要导出的常量、函数放入其中,最后返回这个

[转帖]lua-book-常用库介绍

http://me.52fhy.com/lua-book/chapter7.html String 库 .. 链接两个字符串 string.upper(argument) 字符串全部转为大写字母。 string.lower(argument) 字符串全部转为小写字母。 string.len(arg)

[转帖]lua-book-文件操作

http://me.52fhy.com/lua-book/chapter8.html Lua I/O 库用于读取和处理文件。分为简单模式、完全模式。 简单模式(simple model) 拥有一个当前输入文件和一个当前输出文件,并且提供针对这些文件相关的操作。 完全模式(complete model

[转帖]Ngx_lua

http://me.52fhy.com/lua-book/chapter12.html 简介 ngx_lua 指的是 lua-nginx-module模块:通过将 LuaJIT 的虚拟机嵌入到 Nginx 的 worker 中,这样既保持高性能,又能不失去lua开发的简单特性。 OpenResty 

[转帖]Redis里使用Lua

http://me.52fhy.com/lua-book/chapter11.html 版本:自2.6.0起可用。 时间复杂度:取决于执行的脚本。 使用Lua脚本的好处: 减少网络开销。可以将多个请求通过脚本的形式一次发送,减少网络时延。 原子操作。redis会将整个脚本作为一个整体执行,中间不会被