zoukankan      html  css  js  c++  java
  • chapter 13_1 算术类的元方法

      假设用table来表示集合,用function去计算集合的交集、并集。

    为了保持名称空间的整齐,将这些函数存入一个名为Set的table中。

    现在,假设用“+”来计算两个集合的并集,那么就要让所有用于表示集合的table共享一个元表。

    并且在该元表中定义如何执行一个加法操作。

    local mt = {}     --集合的元表
    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:00672B60
    print(getmetatable(s2))            -->table:00672B60

    最后将元方法加入到元表中:

    mt.__add = Set.union

    元方法就是一个函数:

    Set = {}
    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] = e
        end
        return "{" .. table.concat(l,", ") .. "}"
    end
    
    function Set.print(s)
        print(Set.tostring(s))
    end

    此后,只要Lua试图将两个集合相加,就会调用Set.union函数,并将两个操作数作为参数传入。可以使用加号来求集合的并集:

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

    类似还可以用乘号来求集合的交集:

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

    在元表中,每种算术操作符都有对应的字段名。除了上面的__add和 __mul外,还有__sub,__div、__unm(相反数)、__mod(取模)和__pow(乘幂)。

    此外,还可以定义__concat字段,用于描述连接操作符的行为。

    然而,当一个表达式中混合了具有不同元表的值时,例如:

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

    Lua会按照下面步奏去找元表:

    如果第一个值有元表,并且元表中有__add字段,那么Lua就以这个字段为元方法,而与第二个值无关;

    反之,如果第二个值有元表并包含__add字段,Lua就以它为元方法;

    如果两个都没有元方法,Lua就引发一个错误。

    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
      <as before>

    注意,error的第二个参数用于指示哪个函数调用造成了该错误消息。

    以上内容来自:《Lua程序设计第二版》和《Programming in Lua  third edition 》

  • 相关阅读:
    【BZOJ4637】期望 Kruskal+矩阵树定理
    IEnumerable是什么
    (转)IIS windows认证
    使用pgrouting进行最短路径搜索
    Nginx设置防止IP及非配置域名访问
    java 调用c# web api 代码
    一台机器部署多个tomcat服务 nginx反向代理多个服务 笔记
    利用Kettle 从Excel中抽取数据写入SQLite
    sql server 统计信息
    sql server 索引碎片相关问题
  • 原文地址:https://www.cnblogs.com/daiker/p/5843060.html
Copyright © 2011-2022 走看看