2010-05-11 2 views
9

Я нашел несколько мест в Интернете, в которых говорится, что операторы в Lua являются перегружаемыми, но я не могу найти ни одного примера.

Перегрузка оператора Lua

Может ли кто-нибудь предоставить пример, например, перегрузки оператора +, чтобы работать как оператор .. работает для конкатенации строк?

EDIT 1: Александр Гладыш и RBerteig:
Если оператор перегрузка работает только, когда оба операнд имеет один и тот же тип и изменения такого поведения не было бы легко, то как же Следующий код работает ? (Я не имею в виду какое-либо правонарушение, я только начал изучать этот язык):

printf = function(fmt, ...) 
    io.write(string.format(fmt, ...)) 
end 

Set = {} 
Set.mt = {} -- metatable for sets 

function Set.new (t) 
    local set = {} 
    setmetatable(set, Set.mt) 
    for _, l in ipairs(t) do set[l] = true end 
    return set 
end 


function Set.union (a,b) 
    -- THIS IS THE PART THAT MANAGES OPERATOR OVERLOADING WITH OPERANDS OF DIFFERENT TYPES 
    -- if user built new set using: new_set = some_set + some_number 
    if type(a) == "table" and type(b) == "number" then 
     print("building set...") 
     local mixedset = Set.new{} 
     for k in pairs(a) do mixedset[k] = true end 
     mixedset[b] = true 
     return mixedset 
    -- elseif user built new set using: new_set = some_number + some_set 
    elseif type(b) == "table" and type(a) == "number" then 
     print("building set...") 
     local mixedset = Set.new{} 
     for k in pairs(b) do mixedset[k] = true end 
     mixedset[a] = true 
     return mixedset 
    end 

    if getmetatable(a) ~= Set.mt or 
     getmetatable(b) ~= Set.mt then 
     error("attempt to 'add' a set with a non-set value that is also not a number", 2) 
    end 

    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.tostring (set) 
    local s = "{" 
    local sep = "" 
    for e in pairs(set) do 
     s = s .. sep .. e 
     sep = ", " 
    end 
    return s .. "}" 
end 

function Set.print (s) 
    print(Set.tostring(s)) 
end 

s1 = Set.new{10, 20, 30, 50} 
s2 = Set.new{30, 1} 

Set.mt.__add = Set.union 

-- now try to make a new set by unioning a set plus a number: 
s3 = s1 + 8 
Set.print(s3) --> {1, 10, 20, 30, 50} 
+1

Это справедливо для операторов сравнения - не регулярных операторов. Например, перегрузка, чтобы добавить как таблицу, так и строку, является абсолютно допустимой. – Puppy

ответ

11

metatable функция работает только на столах, но вы можете использовать debug.metatable для установки строки Метастабильную ...

> mt = {} 
> debug.setmetatable("",mt) 
> mt.__add = function (op1, op2) return op1 .. op2 end 
> ="foo"+"bar" 
foobar 
> 

Другой подход заключается в использовании debug.getmetatable увеличить встроенную строку метатаблицу (отвечая на вопрос в комментариях ниже):

~ e$ lua 
Lua 5.1.4 Copyright (C) 1994-2008 Lua.org, PUC-Rio 
> debug.getmetatable("").__add = function (op1, op2) return op1 .. op2 end 
> ="foo"+"bar" 
foobar 
> 
+5

@Pessimist: Обратите внимание, что, хотя он работает, вероятно, это плохая практика, чтобы изменить эту метатегу таким образом. Не адаптируйте язык к вашим старым привычкам - всегда полезно изменить привычки в долгосрочной перспективе. –

+2

Обратите внимание, что этот пример заменяет существующий метатебель для строк, который является (обычно) модулем 'string', так что глобальные запросы не нужны для большинства действий над строками. Вместо этого можно было бы добавить метод '__add' в существующий metatable, используя' debug.getmetatable' для его получения. Как говорит Александр, однако, это не обязательно хорошая идея. – RBerteig

+0

@ Александр Гладыш: Спасибо за совет, но я просто пытаюсь понять, на что способен Луа. Мне нравится концепция DSL (доменных языков), поэтому я, вероятно, буду злоупотреблять этими функциями. :) – PeterM

5

См. Раздел Metatables раздела «Руководство по программированию Lua» и «Метатеги и метаметоды» в Программе в 2-й редакции Lua.

Обратите внимание, что для операторов сравнения перегрузки операторов работает только когда оба типа операндов такой же.

+1

Точка о типе операнда не может быть подчеркнута достаточно. Это отличается от многих других языков, которые поддерживают перегрузку. Сменить это было бы нелегко. – RBerteig

+0

Спасибо за ссылки. См. РЕДАКТИРОВАНИЕ 1 выше. – PeterM

+0

Это справедливо только для операторов сравнения. Это не относится к родовым операторам. Ваша опубликованная ссылка устарела на шесть лет. – Puppy

Смежные вопросы