算数运算相关的元方法

本文涉及的产品
图片翻译,图片翻译 100张
语种识别,语种识别 100万字符
文本翻译,文本翻译 100万字符
简介: 算数运算相关的元方法

假设有一个用表来表示集合的模块,该模块还有一些用来计算集合并集和交集等的函数,如下所示:

local Set = {}
-- 使用指定的列表创建一个新的集合
function Set.new (l)
  local set = {}
  for _, v in ipairs(l) do set[v] = true end
  return set
end
function Set.union (a, b)
  local res = Set.new{}
  for k in pairs(a) do res[k] = true end
  for k in pairs(b) do res[k] = true end
  return res
end
function Set.intersection (a, b)
  local res = Set.new{}
  for k in pairs(a) do res[k] = b[k]end
  return res
end
-- 将集合表示为字符串
function Set.tostring(set)
  local l = {}  -- 保存集合中所有元素的列表
  for e in pairs(set) do l[#l + 1] = tostring(e) end
  return "{" .. table.concat(l, ", ") .. "}"
end
return Set


现在,假设使用加法操作符来计算两个集合的并集,那么可以让所有表示集合的表共享一个元素。这个表中定义了这些表应该如何执行加法操作。首先,我们创建一个普通的表,这个表被用作集合的元表:

local mt = {}


然后,修改用于创建集合的函数 Set.new 。在新版本中只多了一行,即将 mt 设置为函数 Set.new 所创建的表的元表:

function Set.new (l)    -- 第二个版本
  local set = {}
  setmetatable(set, mt)
  for _, v in ipairs(l) do set[v] = true end
  return set
end


在此之后,所有由 Set.new 创建的集合都具有了一个相同的元表:

s1 = Set.new {10,20,30,50}
s2 = Set.new{30,1}
print(getmetatable(s1))   --> table: 0x00672B60
print(getmetatable(s2))   --> table: 0x00672B60


最后,向元表中加入元方法__add ,也就是用于描述如何完成加法的字段:

mt.__add = Set.union


此后,只要 Lua 语言试图将两个集合相加,他就会调用函数 Set.union ,并将两个操作数作为参数传入。


通过元方法,我们就可以使用加法运算符来计算集合的并集了:

s3 = s1 + s2
print(Set.tostring(s3))   --> {1, 20, 20, 30, 50}


类似的,还可以使用乘法运算符来计算集合的交集:

mt.__mul = Set.intersection
print(Set.tostring(s1 + s2) * s1) --> {10, 20, 30, 50}


每种算数运算符和位操作都有一个对应的元方法。如下所示:

算数运算 元方法
加法 __add
乘法 __mul
除法 __div
减法 __sub
floor除法 __idiv
负数 __unm
取模 __mod
幂运算 __pow
按位与 __band
按位或 __bor
按位异或 __bxor
按位取反 __bnot
向左移位 __shl
向右移位 __shr


当我们把两个集合相加时,使用那个元表是确定的。然而,当一个表达式中混合了两种具有不同元表的值时,例如:

s = Set.new{1,2,3}
s = s + 8


Lua 语言会按照如下步骤来查找元方法:

如果第一个值有元表且元表中存在所需的元方法,那么 Lua 语言就会使用这个元方法,与第二个值无关;如果第二个值有元表且元表中存在所需的元方法, Lua 语言就使用这个元方法;否则, Lua 语言就抛出异常。因此,上例会调用 Set.union ,而表达式 10 + s"hello" + s 同理(由于数值和字符串都没有元方法 __add )。


Lua 语言不关心这些混合类型,但我们在实现中需要关系混合类型。如果我们执行了 s = s + 8 ,那么在 Set.union 内部就会发生错误:

bad argument #1 to 'pairs' (table expected, got number)


如果想要得到更加明确的错误信息,则必须在试图进行操作前显式地检查操作数的类型,例如:

function Set.union(a, b)
  if getmetatable(a) ~= mt or getmetatable(b) ~= mt then
    error("attempt to 'add' a set with a non-set value", 2)
  end
  -- 同前面


注意

函数 error 的第二个参数说明了出错的原因位于调用该函数的代码中。

目录
相关文章
|
5月前
|
JavaScript 前端开发 大数据
数字太大了,计算加法、减法会报错,结果不正确?怎么办?用JavaScript实现大数据(超过20位的数字)相加减运算。
数字太大了,计算加法、减法会报错,结果不正确?怎么办?用JavaScript实现大数据(超过20位的数字)相加减运算。
|
12月前
|
存储 数据处理
计算机数据的表示及运算
计算机数据的表示和运算是计算机系统中非常重要的概念。计算机使用二进制来表示和处理数据,其中包括整数、浮点数和字符等不同类型的数据。下面将详细介绍计算机数据的表示和运算。 1. 二进制表示:计算机使用二进制系统来表示数据。二进制系统由0和1两个数字组成,每一位称为一个比特(bit)。比特是计算机中最小的存储单位,可以表示一个二进制数值(0或1)。 2. 整数表示:计算机使用补码表示整数。补码是一种用于表示负数的方法,它将负数的最高位设为1,正数的最高位设为0。补码表示可以保证负数的运算结果仍然是有效的。 3. 浮点数表示:计算机使用浮点数表示实数。浮点数由两个部分组成:尾数和指数。尾数表示
153 0
|
5月前
|
机器学习/深度学习 存储 算法
位运算是一种什么运算方式
位运算是一种什么运算方式
35 1
|
12月前
|
存储 算法 数据处理
数据的表示及运算
一、数据的表示及运算 数据的表示和运算是计算机系统中非常重要的概念,它们决定了计算机如何处理和操作数据。 1. 数据的表示:计算机使用二进制(0和1)来表示和存储数据。二进制是一种只有两个状态的编码方式,可以通过开关电路的开和关来表示0和1。计算机将二进制编码与不同的数据类型关联,例如整数、浮点数、字符等。 2. 整数运算:计算机可以对整数进行基本的算术运算,包括加法、减法、乘法和除法。这些运算是通过电子电路中的逻辑门实现的,逻辑门可以对二进制数进行逻辑运算和移位操作。 3. 浮点数运算:计算机可以进行浮点数的运算,浮点数是一种用于表示带有小数部分的数值的数据类型。浮点数运算涉及到浮点数的表示
69 0
|
人工智能 测试技术
MoonLight的运算问题
MoonLight的运算问题
88 0
|
算法
不使用+或-运算符,计算两数之和
不使用+或-运算符,计算两数之和
74 0
关系运算相关的元方法
关系运算相关的元方法
59 0
算数运算
算数运算
126 0
7-237 有理数加法 (15 分)
7-237 有理数加法 (15 分)
96 0