【问题标题】:Lua: __lt metamethod setting is not working how I wantLua:__lt 元方法设置无法正常工作
【发布时间】:2011-12-22 22:55:57
【问题描述】:

这是我对这个令人难以置信的社区的第一个问题。

这些天来,我正在为自己编写一个 Lua 模块。这是有问题的代码的最小部分

mt = {}

bf = {}

------------
-- bf.new --
------------
function bf.new(A)

    local out = A
    setmetatable(out,mt)
    return out

end

-----------------
-- bf.tostring --
-----------------
function bf.tostring(A)

    local typeA = type(A)
    local out   = ""
    if typeA=="number" or typeA=="boolean" then
        print(tostring(A))
    elseif typeA=="table" then
        local col    = ""
        local m      = #A
        local typeA1 = type(A[1])
        for i=1,m do
            if typeA1=="table" then
                n = #A[1]
                for j=1,n do
                    out = out.." "..tostring(A[i][j])
                    if j==n then
                        out = out.."\n"
                    end
                end
            elseif (typeA1=="number" or typeA1=="boolean") then
                row = row.." "..tostring(A[i][j])
            end
        end
    end
    return out
end

-----------------------------
-- bf.compare(A,logical,B) --
-----------------------------
function bf.compare(A,logical,B)

    if (logical~="<"  and
        logical~=">"  and
        logical~="<=" and
        logical~=">=" and
        logical~="==" and
        logical~="~=") then
        error("second input input must be a logical operator written into a string")
    end
    local out   = {}
    local ind   = {}
    local count = 0
    if type(B)=="number" then
        if type(A[1])=="table" then
            for i=1,#A do
                out[i] = {}
                for j=1,#A[1] do
                    loadstring("cond ="..A[i][j]..logical..B)()
                    if cond then
                        out[i][j]  = true
                        count      = count+1
                        ind[count] = (i-1)*#A[1]+j
                    else
                        out[i][j]  = false
                    end
                end
            end
        elseif type(A[1])=="number" then
            for j=1,#A do
                loadstring("cond ="..A[j]..logical..B)()
                if cond then
                    out[j]     = true
                    count      = count+1
                    ind[count] = j
                else
                    out[j]     = false
                end
            end
        end
    else
        if (type(A[1])=="table" and type(B[1])=="table") then
            if (#A==#B and #A[1]==#B[1]) then
                for i=1,#A do
                    out[i] = {}
                    for j=1,#A[1] do
                        loadstring("cond ="..A[i][j]..logical..B[i][j])()
                        if cond then
                            out[i][j]  = true
                            count      = count+1
                            ind[count] = (i-1)*#A[1]+j
                        else
                            out[i][j] = false
                        end
                    end
                end
            else
                error("The comparison can be done between "..
                      "two matrix with same dimension "..
                      "or between a matrix with a scalar value")
            end
        elseif (type(A[1])=="number" and type(B[1])=="number") then
            if (#A==#B) then
                for j=1,#A do
                    loadstring("cond ="..A[j]..logical..B[j])()
                    if cond then
                        out[j] = true
                        count      = count+1
                        ind[count] = j
                    else
                        out[j] = false
                    end
                end
            else
                error("Comparison between "..
                      "two vector with different dimension")
            end
        else
            error("The comparison can be done between "..
                  "two matrix with same dimension "..
                  "or between a matrix with a scalar value")
        end
    end
    return setmetatable(out,mt)--,ind

end

------------------------
-- metamethod setting --
------------------------
mt.__tostring = bf.tostring
mt.__lt       = function(A,B) return bf.compare(A,"<",B) end

--------------------------
-- use of my metamethod --
--------------------------
A  = bf.new{{1,2,3,4},{5,6,7,8},{9,10,11,12}}
B  = bf.new{{3,6,1,8},{1,3,87,20},{11,2,5,7}}
C1 = bf.compare(A,"<",B)
C2 = A<B
print("What I want")
print(C1)
print("What I get")
print(C2)

如果你运行这个小脚本,你可以看到当我直接使用函数 bf.compare 时,我得到了我需要的东西。当我通过元方法使用 bf.compare 时,它​​只给了我一个 true 的“标量”值。

有什么建议吗?

编辑

这是输出:

What I want
 true true false true
 false false true true
 true false false false

What I get
true
>Exit code: 0

【问题讨论】:

  • 我根本看不到,因为你没有显示输出。
  • +1 用于实际提供工作代码。

标签: lua


【解决方案1】:

Lua manual 声明了 __lt metamethod 的伪代码:

function lt_event (op1, op2)
       if type(op1) == "number" and type(op2) == "number" then
         return op1 < op2   -- numeric comparison
       elseif type(op1) == "string" and type(op2) == "string" then
         return op1 < op2   -- lexicographic comparison
       else
         local h = getbinhandler(op1, op2, "__lt")
         if h then
           return not not h(op1, op2)
         else
           error(···)
         end
       end
     end

如果存在元方法,则此行 return not not h(op1, op2) 仅返回处理程序 h 返回的单个(第一个)值,因为 not 是一元运算符。作为第二个效果,它将处理程序输出转换为标量:not {} == falsenot false == true

另一个需要注意的小事:Lua 表总是通过引用传递。将表分配给另一个变量只会导致复制指针。因此,如果您执行以下操作:

function myFun(A)
    local out=A
    out[1]='bar'
    return out
end
A={'foo',1,2,3}
B=myFun(A)
print(table.concat(B,', ')) -- OK
print(table.concat(A,', ')) -- A also changed, because:
print(A,B) -- they are the same table!

【讨论】:

    【解决方案2】:

    所有比较元方法的结果都会自动转换为布尔值。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2017-09-03
      • 2017-08-13
      • 1970-01-01
      • 1970-01-01
      • 2013-02-08
      • 2014-09-28
      • 1970-01-01
      • 2023-02-19
      相关资源
      最近更新 更多