Question

J'ai mis en place mon propre système de classe et j'ai de la difficulté avec __tostring;Je soupçonne un problème similaire peut se produire avec d'autres metamethods, mais je n'ai pas essayé.

(Bref détour:chaque classe a un __classDict attribut, la tenue de toutes les méthodes.Il est utilisé comme la classe des instances __index.Dans le même temps, l' __classDict de l' __index est la super-classe' __classDict, afin que les méthodes des super-classes sont authomatically leva les yeux.)

Je voulais avoir un "défaut tostring" comportement dans tous les cas.Mais il ne fonctionne pas:le "tostring" le comportement n'est pas la "propagation" à travers les sous-classes correctement.

J'ai fait ce test illustrer mon problème:

mt1 = {__tostring=function(x) return x.name or "no name" end }
mt2 = {}
setmetatable(mt2, {__index=mt1})
x = {name='x'}
y = {name='y'}
setmetatable(x, mt1)
setmetatable(y, mt2)
print(x) -- prints "x"
print(mt2.__tostring(y)) -- prints "y"
print(y) -- prints "table: 0x9e84c18" !!

J'aurais plutôt que la dernière ligne d'impression "y".

Arus "to_String" comportement doit être à l'aide de l'équivalent de

rawget(instance.class.__classDict, '__tostring')

au lieu de faire l'équivalent de

instance.class.__classDict.__tostring

Je soupçonne la même chose se produit avec tous les metamethods; rawget-des opérations équivalentes sont utilisées.

Je suppose que une seule chose que je puisse faire est de copier tous les metamethods quand je fais mes sous-classement (l'équivalent sur l'exemple ci-dessus serait de faire mt2.__tostring = mt1.__tostring), mais c'est à peu élégante.

Quelqu'un a combattu avec ce genre de problème?Quels sont vos solutions?

Était-ce utile?

La solution 2

Grâce à daurnimator les commentaires, je crois que j'ai trouvé un moyen de faire metamethods "suivre" __index comme je voudrais.C'est condensée sur cette fonction:

local metamethods = {
  '__add', '__sub', '__mul', '__div', '__mod', '__pow', '__unm', '__concat', 
  '__len', '__eq', '__lt', '__le', '__call', '__gc', '__tostring', '__newindex'
}

function setindirectmetatable(t, mt) 
  for _,m in ipairs(metamethods) do
    rawset(mt, m, rawget(mt,m) or function(...)
      local supermt = getmetatable(mt) or {}
      local index = supermt.__index
      if(type(index)=='function') then return index(t,m)(...) end
      if(type(index)=='table') then return index[m](...) end
      return nil
    end)
  end

  return setmetatable(t, mt)
end

J'espère que c'est assez simple.Lorsqu'un nouveau métatable est défini, il l'initialise avec tous les metamethods (sans remplacement de ceux existants).Ces metamethods sont prêts à "passer" les demandes de "parent metatables".

C'est la solution la plus simple que j'ai pu trouver.Eh bien, j'ai effectivement trouvé une solution qui a utilisé moins de personnages et était un peu plus rapide, mais il s'agit de magie noire (elle a impliqué métatable fonctions de référence eux-mêmes à l'intérieur de leur propre corps) et c'était beaucoup moins lisible que celui-ci.

Si quelqu'un trouve un plus court, plus simple fonction qui fait la même chose, je serai heureux de lui donner la réponse.

L'utilisation est simple:remplacer setmetatable par setindirectmetatable quand vous voulez à "aller":

mt1 = {__tostring=function(x) return x.name or "no name" end }
mt2 = {}
setmetatable(mt2, {__index=mt1})
x = {name='x'}
y = {name='y'}
setmetatable(x, mt1)
setindirectmetatable(y, mt2) -- only change in code
print(x) -- prints "x"
print(mt2.__tostring(y)) -- prints "y"
print(y) -- prints "y"

Un petit mot d'avertissement: setindirectmetatable crée metamethods sur mt2.Changer ce comportement par conséquent, une copie est faite, et mt2 reste inchangé, devrait être trivial.Mais les laisser définir par défaut est en fait mieux pour mes fins.

Autres conseils

Je soupçonne la même chose se produit avec tous les metamethods;rawget-opérations équivalentes sont utilisées.

Qui est correct.à partir de la lua manuel:

...doit être lu comme rawget(getmetatable(obj) or {}, event).Qui est, l'accès à un metamethod de ne pas se prévaloir d'autres metamethods, et l'accès à des objets sans metatables de ne pas échouer (il simplement des résultats dans le néant).

En général, chaque classe a ses propres métatable, et vous copiez toutes les références à des fonctions.C'est, ne mt2.__tostring = mt1.__tosting

De mon expérience avec Lua 5.1, metamethods sont recherchés dans metatables à l'aide de rawget(), et c'est pourquoi vous doit copie de la référence à la fonction dans toutes les classes de la table que vous créez.

Voir la L'Héritage Tutoriel sur le Lua Utilisateurs de Wiki.

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top