2011-12-22 19 views
5

Đây là câu hỏi đầu tiên của tôi cho cộng đồng đáng kinh ngạc này.Cài đặt metamethod Lua: __lt không hoạt động như thế nào Tôi muốn

Trong những ngày này tôi đang viết mô-đun Lua cho chính tôi. Ở đây nó là một phần tối thiểu của mã với vấn đề

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) 

Nếu bạn chạy kịch bản này chút, bạn có thể thấy rằng khi tôi sử dụng chức năng bf.compare trực tiếp tôi có những gì tôi cần. Khi tôi sử dụng bf.compare thông qua metamethod, nó mang lại cho tôi chỉ một giá trị "vô hướng" của sự thật.

Bất kỳ đề xuất nào?

EDIT

Dưới đây là kết quả:

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

What I get 
true 
>Exit code: 0 
+0

Tôi thực sự không thể thấy điều đó vì bạn không hiển thị đầu ra. – Puppy

+1

+1 để thực sự cung cấp mã làm việc. – jpjacobs

Trả lời

4

Các Lua manual bang này mã giả cho __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 

nếu có một metamethod, sau đó dòng này return not not h(op1, op2) chỉ trả về giá trị singel (giá trị đầu tiên) được trả về bởi trình xử lý h, như not là một toán tử đơn nhất. Như một hiệu ứng thứ hai, nó chuyển đổi kết quả xử lý thành vô hướng: not {} == falsenot false == true.

Một điều nhỏ khác cần lưu ý: Bảng Lua luôn được chuyển bằng tham chiếu. Việc gán một bảng cho một biến khác chỉ dẫn đến việc sao chép con trỏ. Do đó, nếu bạn thực hiện các công cụ như:

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

Kết quả của tất cả các metamethod được so sánh tự động được chuyển thành boolean.

Các vấn đề liên quan