2010-05-11 11 views
9

J'ai trouvé quelques endroits sur le web disant que les opérateurs de Lua sont surchargeables mais je n'arrive pas à trouver d'exemple. Est-ce que quelqu'un peut donner un exemple de surcharger l'opérateur + pour qu'il fonctionne comme l'opérateur .. fonctionne pour la concaténation de chaînes?

Lua Operator Overloading

EDIT 1: Alexander Gladysh et RBerteig:
Si l'opérateur surcharge ne fonctionne que lorsque les deux opérandes sont du même type et de changer ce comportement ne serait pas facile, alors comment se fait les travaux de code suivant ? (Je ne veux pas une infraction, je viens de commencer l'apprentissage de cette langue):

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

Cela est vrai pour les opérateurs de comparaison - pas pour les opérateurs habituels. La surcharge pour ajouter à la fois une table et une chaîne, par exemple, est parfaitement valide. – Puppy

Répondre

11

La fonction metatable ne fonctionne que sur les tables, mais vous pouvez utiliser debug.metatable pour définir les chaînes MetaTable ...

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

Une autre approche consiste à utiliser debug.getmetatable pour augmenter la métatable chaîne intégrée (répondant à la question dans le commentaire ci-dessous):

~ 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: Notez que, bien que cela fonctionne, il est probablement une mauvaise pratique de changer la chaîne de caractères de cette manière. N'adaptez pas le langage à vos vieilles habitudes - il est toujours plus productif de changer les habitudes à long terme. –

+2

Notez que l'exemple remplace la métatable existante pour les chaînes, qui est (généralement) le module 'string' de sorte que les recherches globales ne sont pas nécessaires pour la plupart des actions sur les chaînes. Il serait possible d'ajouter la méthode '__add' à la métatable existante en utilisant' debug.getmetatable' pour la récupérer. Comme Alexander dit, ce n'est pas nécessairement une bonne idée de faire vraiment, cependant. – RBerteig

+0

@Alexander Gladysh: merci pour le conseil mais j'essaie juste de voir de quoi Lua est capable. J'aime le concept de DSL (les langages spécifiques au domaine), donc je vais probablement abuser de ces fonctionnalités. :) – PeterM

5

Voir la section Metatables du manuel de programmation Lua et le chapitre Metatables and Metamethods de la programmation en Lua 2e édition.

Notez que pour la surcharge des opérateurs des opérateurs de comparaison fonctionne uniquement lorsque les deux types d'opérandes sont les mêmes.

+1

Le point sur le type d'opérande ne peut pas être assez souligné. Ceci est différent de quelques autres langues qui supportent la surcharge. Changer cela ne serait pas facile non plus. – RBerteig

+0

Merci pour les liens. S'il vous plaît voir EDIT 1 ci-dessus. – PeterM

+0

Cela n'est vrai que pour les opérateurs de comparaison. Ce n'est pas vrai pour les opérateurs génériques. Votre lien posté a six ans de retard. – Puppy