Concepts avancés de Lua.
Récupération de la mémoire utilisée
Objets inaccessibles
Dans les langues telles que C et C++, des objets que nous créons au temps d'exécution (par exemple employer malloc() ou new) doivent être explicitement supprimés. Les fuites de mémoire sont le résultat des objets étant assignés, obtenant perdues et non jamais libérées. Il est possible d'écrire les systèmes de piste de mémoire qui assignent la
mémoire pour nous et savent quand nous n'avons besoin plus d'elle. Quelques langues ont ce dispositif incorporé, y compris Lua.
Il y a de diverses manières dont du cheminement des objets de mémoire ne sont plus eu besoin. Une fois aucun d'des variables d'applications ne met en référence un objet qu'elle serait inaccessible. Objets qui ne sont plus accessibles devenus deleteable et sont des candidats pour la disposition automatique, ou collection d'ordures.
Dans les exemples suivants nous créons quelques objets de Lua et leur assignons à l'des variables. Si nous assignons d'autres valeurs aux variables, et aucune autre variable ne met en référence les objets précédents, ils deviennent inaccessibles. Si elle n'étaient pas pour la collection d'ordures ceci causerait une fuite de mémoire. Par exemple,
> t = {this="table" ; 1.2.3} -- construisez
une table et assignez-l'à "t" > t = zéro -- placent "t" à zéro et
à la table devient inaccessible > > s = "une corde" -- créez la variable de corde > le s = une "autre corde" -- quand
l'ensemble à
l'autre valeur la vieille valeur devient inaccessible
Algorithmes simples de collection
Il y a de divers types de collecteurs et beaucoup de terminologie lié à la collection
d'ordures [ 1 ]. Un des algorithmes de collection les plus simples est compte de référence. Ici nous maintenons juste un compte dans chaque objet assigné, du nombre d'objets le mettant en référence (ou l'employant). Si le nombre d'objets mettant en référence un autre objet tombe à zéro il devient inaccessible (et inutilisé) et peut être libéré. Une légère complication avec ceci est mise en référence cyclique, où l'objet A met en référence l'objet B, et B met en référence A. C'est très bien aussi longtemps que d'autres objets mettent en référence A et/ou B, mais quand ils pas plus, A et B formeront une île. Ils sont maintenant un groupe d'objets qui sont inaccessibles et mutuellement permanents en raison de la mise en référence cyclique. L'île ne sera jamais libérée à moins que la référence comptant l'algorithme de collection soit augmentée. Par exemple,
> a = {} > b = {} > a['other '] = b > b['other '] = a -- maintenant nous avons une référence
> un a,b = un zéro cycliques, zéro -- l'OH cher, nous n'avons pas une référence aux 2 tables maintenant
> -- il y a deux tables qui sont inaccessibles
Marque et champ
Se débarasser des îles de l'algorithme décrit ci-dessus que nous pourrions voyager par toutes les variables dans notre système et voir quels objets ils mettent en référence. Si objets de trouvaille de variables les certains inaccessibles nous des ordures de bidon les rassemblent. Cet algorithme s'appelle la marque et champ, c.-à-d., nous marquons tous
les objets accessibles et balayons loin ceux restants. Lua emploie l'algorithme de marque et de collection d'ordures de champ exclusivement. Ceci a l'avantage que nous ne devons pas mettre en référence des objets de compte et ainsi n'obtient pas la répétition mettant en référence des problèmes. Un inconvénient est que l'algorithme prend du temps de traiter et peut être une issue dans des applications en temps réel.
Note: Si nous devions distribuer le traitement de la marque et balayer l'algorithme de
collection, de sorte qu'il n'ait pas été tout fait immédiatement, il serait plus transparent au système hôte. Ceci s'appelle collection par accroissement d'ordures. Ce changement est projeté pour la version 5.1 de Lua.
Commande et statut
Lua fournit quelques fonctions pour commander et questionner le statut de collection d'ordures. Il y a plus de détails dans le CoreFunctionsTutorial.
collectgarbage([limit]) place le seuil auquel la collection d'ordures est lancée. Elle peut s'appeler sans arguments pour forcer une collection immédiate.
gcinfo() retours deux nombres : la quantité de mémoire que Lua a assignée et du seuil courant de collecteur d'ordures. Tous les deux sont en K bytes.
Plus de lecture
D'autres pages sur le wiki couvrent la collection d'ordures dans Lua en plus détail. Ce qui suit est lecture suggérée :
GarbageCollection - liens et information généraux sur des matières de collection d'ordures.
OptimisingGarbageCollection - notes sur la collection réduisante au minimum d'ordures et le traitement impliqué, si c'est une issue. Vous pourriez également vouloir lire OptimisationTips.
GarbageCollectionInRealTimeGames - plus de notes sur la collection d'ordures dans le détail de Lua à la programmation de jeux.
Cours d'instruction de Coroutines
Que sont les coroutines ?
Coroutines nous permettent d'exécuter plusieurs charge immédiatement. Ceci est fait d'une façon commandée en passant la main à chaque routine et l'attente jusqu'à ce que le courant indique de lui a fini. Nous pouvons réintroduire la routine pour continuer à un temps postérieur et en faisant ceci à plusieurs reprises nous réalisons multi-charger.
Multi-filetage
Chacun charge des courses dans un fil qui est séparé des autres fils. Ayant plusieurs charge le fonctionnement immédiatement s'appelle souvent multi-filetage. Puisqu'il y a plus d'un fil courant immédiatement notre application serait multi-fileté.
Il y a de différentes manières dont le multi-filetage peut être mis en application. Quelques systèmes assignent une quantité de temps fixe à chaque fil et enlèvent la commande quand le temps est en hausse, transmettant la commande au prochain fil etc... Ceci s'appelle multi-filetage de préemption. Dans ce cas-ci chacun des fils n'a pas besoin de s'inquiéter combien d'heure il occupe, il davantage est concerné par sa propre fonction.
Dans d'autres systèmes, un fil est concerné par combien de temps il prend. Le fil sait qu'il doit passer la main à d'autres fils de sorte qu'ils puissent fonctionner aussi bien. C'est s'appelle coopérative, ou multi-filetage de collaboration. Ici, tous les fils collaborent ensemble pour permettre à l'application de fonctionner correctement. C'est le type de multi-charger que les coroutines de Lua emploient.
Coroutines dans Lua ne sont pas des fils ou des processus de logiciel d'exploitation. Coroutines sont des blocs de code de Lua qui sont créés dans Lua, et ont leur propre écoulement de commande comme des fils. Seulement un coroutine fonctionne jamais à la fois, et il fonctionne jusqu'à ce qu'il active un autre coroutine, ou rapporte (des retours au coroutine qui l'a appelé). Coroutines sont une manière d'exprimer les fils de coopération multiples de la commande en manière commode et normale, mais ne s'exécutent pas en parallèle, et ne gagnent ainsi aucun avantage d'exécution de CPU's multiple. Cependant, depuis des coroutines commutez beaucoup plus rapidement que des fils de logiciel d'exploitation et n'exigez pas typiquement le complexe et les dispositifs de verrouillage parfois chers, employant des coroutines est en général plus rapide que le programme équivalent en utilisant de pleins fils d'OS.
Rendement
Afin coroutines multiples pour partager l'exécution qu'ils doivent cesser s'exécuter (après avoir effectué une quantité sensible de traitement) et passer la main à un autre fil. Cet acte de la soumission s'appelle rendement. Coroutines appellent explicitement une fonction de Lua coroutine.yield(), qui est semblable à employer return dans les fonctions. Ce qui différencie le rendement des retours de fonction est celui à un point postérieur que nous pouvons réintroduire le fil et continuer où nous avons cessé. Quand vous sortez une portée de fonction employant return la portée est détruit et nous ne pouvons pas la réintroduire, par exemple,
> foo(x) de fonction > > si x>3 alors
l'extrémité vraie de retour -- nous pouvons sortir la fonction avant
que l'extrémité si besoin en est > > retour faux -- renvoyez une
valeur à la fin de la fonction (facultative) > > extrémité > = foo(1) faux > = foo(100) -- point différent de sortie vrai
Utilisation simple
Pour créer un coroutine nous devons avoir la fonction qui le représente, par exemple, > foo() de fonction > > print("foo", 1) > >
coroutine.yield() > > print("foo", 2) > > extrémité >
Nous créons un coroutine en utilisant coroutine.create(fn) la fonction. Nous lui passons un point d'entrée pour le fil qui est une fonction de Lua. L'objet est retourné par Lua est un
fil:
> les Co = coroutine.create(foo) -- créez un coroutine
avec le foo comme entrée > = type(co) -- montrent le type fil de
l'objet de "Co"
Nous pouvons découvrir quel état le fil est en employant coroutine.status() la fonction, par exemple,
> = coroutine.status(co) suspendu
L'état a suspendu des moyens que le fil est vivant, et car vous prévoiriez, ne
faisant pas quelque chose. Notez que quand nous avons créé le fil il n'a pas
commencé à s'exécuter. Pour commencer le fil nous
employons
coroutine.resume()la fonction. Lua entrera dans le fil et partira
quand le fil rapporte.
> = coroutine.resume(co) foo 1 vrai
coroutine.resume()
La fonction renvoie le statut d'erreur de l'appel de
résumé. Le rendement reconnaît que nous avons écrit la fonction
fooet
avons puis sorti sans des erreurs. Est maintenant le peu intéressant. Avec
une fonction nous ne pourrions pas continuer où nous avons cessé, mais
avec des coroutines nous pouvons reprendre encore :
> = coroutine.resume(co) foo 2 vrai
Nous pouvons voir que nous avons exécuté la ligne après le rendement
dedans
fooet sommes encore retournés sans erreur. Cependant, si nous
regardons le statut nous pouvons voir que nous avons sorti la
fonction
fooet le coroutine terminés.
> = coroutine.status(co) morts
Si nous essayons de reprendre encore une paire de valeurs est retournée :
un drapeau d'erreur et un message d'erreur :
> = coroutine.resume(co) faux ne peut pas reprendre le coroutine mort
Une fois qu'un coroutine sort ou des retours comme une fonction il ne peut
pas être repris.
Plus de détails
Ce qui suit est un exemple plus compliqué démontrant quelques dispositifs importants des coroutines.
> odd(x) de fonction > > print('A : impair ', x) > >
coroutine.yield(x) > > print('B : impair ', x) > > extrémité > > even(x) de fonction > > print('C : même ', x) > > si
extrémité de retour de x==2 puis x > > print('D : même ', x) > > l'extrémité > > Co = coroutine.create(> > la fonction (x) > >
pour i=1, le x > > si puis coroutine.yield(-1) l'extrémité i==3 > >
si puis extrémité d'autre d'odd(i) de l'even(i) math.mod(i, 2)==0 >
> extrémité > > extrémité) > > compte = 1 > tandis que coroutine.status(co) le ~ = 'complètement ' > > compte du print('----') ; compte = count+1 > > errorfree, valeur = coroutine.resume(co, 5) > > print('E : errorfree, valeur, statuts, errorfree, valeur, coroutine.status(co)) > > extrémité 1 A
: 1 E impair : l'errorfree, valeur, statut rectifient 1 suspendu 2 B : 1 C impair : égalisez 2 E :
l'errorfree, valeur, statut rectifient -1 suspendu 3 A : 3 impairs E : l'errorfree, valeur, statut rectifient 3 suspendus 4
5 impairs E : l'errorfree, valeur, statut rectifient 5 suspendus 5 B : 5 impairs E : errorfree, valeur, zéro vrai de statut mort >
Fondamentalement nous avons for une boucle qui appelle deux fonctions : odd() quand elle rencontre un nombre impair et even() sur des chiffres pairs. Il peut être peu un difficile digérer le rendement ainsi nous étudierons les boucles externes, comptées près count, une par une. Des commentaires ont été ajoutés.
1 A : 1 impair -- rendement de l'odd() E :
l'errorfree, valeur, statut rectifient 1 suspendu
Dans la boucle une nous appelons notre employer de
coroutine
coroutine.resume(co, 5). La première fois qu'il s'appelle nous
écrivons
forla boucle dans la fonction de coroutine. Notez que la
fonction
odd(), qui s'appelle par nos rendements de fonction de coroutine.
Vous ne devez pas rapporter dans la fonction de coroutine. C'est un
dispositif important et utile. Nous renvoyons la valeur de 1 avec le
rendement.
2 B : 1 impair -- résumé dans impair avec les
valeurs que nous avons laissées sur le rendement C : même 2 -- appel égal et sortie pr3maturément E : l'errorfree, valeur, statut rectifient -1 suspendu -- rendement dedans pour la boucle
Dans la boucle 2, la boucle
forprincipale rapporte et suspend le coroutine.
Le point à la note ici est que nous pouvons rapporter n'importe où. Nous ne
devons pas maintenir rapporter d'un point dans notre coroutine. Nous
renvoyons -1 avec le rendement.
3 A : 3 impairs -- l'odd() rapporte encore après
avoir repris dedans pour la boucle E : l'errorfree, valeur, statut rectifient 3 suspendus
Nous reprenons le coroutine dans
forla boucle et quand
odd()s'appelle elle
rapporte encore.
4 B : 3 impairs -- le résumé dans l'odd(), des
valeurs variables a maintenu C : égalisez 4 -- même le
called() D : même 4 -- aucun retour dans l'even() cette fois A : 5 impairs -- odd() appelé et un rendement E :
l'errorfree, valeur, statut rectifient 5 suspendus
Dans la boucle 4, nous reprenons dedans
odd()où nous avons cessé. Notez
que les valeurs variables sont préservées. La portée
odd()de la fonction est
préservée pendant un coroutine suspendent. Nous traversons à la fin
de
even(), cette fois sortant à la fin de la fonction. Dans l'un ou l'autre cas,
quand nous sortons une fonction sans employer
coroutine.yield(), la portée
et toutes ses variables sont détruites. Seulement sur un rendement
pouvons nous reprenons.
5 B : 5 impairs -- encore appelé E impair :
se termine >
De nouveau nous reprenons dedans odd(). Cette fois la boucle for principale atteint la limite de 5 que nous avons passés dans le coroutine. La valeur de 5 et for l'état de boucle ont été préservés dans toute l'exécution du coroutine. Un coroutine préserve sa propres pile et état tandis que dans l'existance. Quand nous sortons notre fonction de coroutine qu'il meurt et nous pouvons plus ne l'employer.
Unité d'éxécution (Threads)
Fils de préemption et Lua
La norme ANSI C, la norme à laquelle Lua se conforme, n'a aucun mécanisme pour
contrôler les fils multiples de l'exécution. Des fils et les objets de synchronisation employés pour les commander sont fournis par le logiciel d'exploitation fondamental. Vous devrez employer ces derniers afin de mettre en application le filetage dans Lua. Vous n'aurez pas besoin de modifier la distribution de Lua pour faire ceci.
Les fils sont rusés pour devenir exacts même dans le plus simple des circonstances telles qu'une application pure de C. Une application qui enfonce ou prolonge Lua doit faire face à la complexité additionnelle des fils coordonnés avec la bibliothèque de Lua. Si vos besoins de traitement multitâche peuvent être rencontrés les coroutines simple-filetés de Lua, vous bien-seriez conseillé de choisir cet itinéraire. Lisez CoroutinesTutorial pour plus de détails. Si vous choisissez de mettre en application les fils de préemption multiples à votre Lua projettent, les directives suivantes peuvent aider.
Chaque fil en C qui agit l'un sur l'autre avec Lua aura besoin de son propre état de Lua. Chacun de ces états a sa propre pile d'exécution. Quand un nouveau fil de C est
commencé, vous pouvez créer son état de Lua dans une de deux manières. L'one-way doit appeler lua_open. Ceci crée un nouvel état qui est indépendant des états en d'autres fils. Dans ce cas-ci, vous devrez initialiser l'état de Lua (par exemple, bibliothèques de programmes) comme si c'était l'état d'un nouveau programme. Cette approche élimine le besoin de serrures de mutex (discutées ci-dessous), mais gardera les fils de partager des données globales.
L'autre approche est d'appeler lua_newthread. Ceci crée un état d'enfant qui a sa propre pile et qui a accès aux données globales. Cette approche est discutée ici.
Fermeture par Lua
Votre plus grand souci quand travailler avec des fils doit les empêcher de corrompre les environnements de chacun. Les problèmes subtiles ou non-ainsi-subtiles, immédiats ou parfois de façon exaspérante retardés, attendent un fil qui revient après le droit de préemption à un environnement qui a été laissé dans un état inattendu par un autre fil. Cependant, vous voulez généralement que les fils partagent certaines structures de données, aussi. C'est où les objets de mutex du logiciel d'exploitation héritent le jeu. Un objet de ce type peut être fermé à clef par pas plus d'un fil à la fois.
Avec de l'aide de vous, Lua empêchera ses structures de données internes d'être corrompue. Quand Lua entre dans une opération qui ne doit pas être appropriée, elle appelle lua_lock. Quand l'opération critique est complète, elle appelle lua_unlock. Dans la distribution de défaut ces deux fonctions ne font rien. Quand employer filète dans Lua, elles devraient être remplacées avec des réalisations OS-DÉPENDANTES. Dans un environnement de POSIX vous emploierez un objet de type pthread_mutex_t. Dans
Windows, vous emploierez l'un ou l'autre une poignée dont est retourné CreateMutex, ou, plus de façon optimale, une structure de données opaque de type CRITICAL_SECTION. Tous les coroutines dans un univers particulier de lua doivent partager le même mutex. Évitez l'erreur d'associer le mutex à un état spécifique de Lua et puis ne la trouvent pas encore quand un coroutine différent dans le même univers est verrouillé. Un exemple simple pour Win32 suit. Le dossier d'en-tête luauser.h contient :
# définissez le lua_lock(L) LuaLock(L) # définissent le lua_unlock(L) LuaUnlock(L) # définissent le
lua_userstateopen(L)
LuaLockInitial(L) # définissent le lua_userstatethread(L, L1) LuaLockInitial(L1)// Lua 5.1 LuaLockInitial(lua_State vide * L) ;
videz LuaLockFinal(lua_State * L) ; videz
LuaLock(lua_State * L) ; videz LuaUnlock(lua_State * L) ;
Les trois définitions de préprocesseur seront employées quand Lua est compilé. En date de la version 5.0.2, Lua regrettablement ne fournit pas un appel pour détruire une serrure. La fonction lua_userstateopen s'appellera toutes les fois qu'un nouvel état de Lua est créé, à si avec un appel lua_open ou lua_newthread. Il est important que le mutex soit créé seulement la première fois lua_userstateopen s'appelle.
Dans Lua 5.1 luai_userstatethread(L,L1) est réclamés des fils créés
avec lua_newthread. et luai_userstateopen(L) est réclamé des états de lua créés près lua_newstate (mais pas près lua_newthread). luai_userstateclose(L) est réclamé des fils fermés près lua_close seulement.
Le dossier associé de C luauser.c, contient :
# incluez < windows.h > # incluent "lua.h" # incluent le struct statique de "luauser.h" {CRITICAL_SECTION LockSct ; BOOL Init ; } Gl ; LuaLockInitial(lua_State vide * L) {si (!
Gl.Ilente) {/* créez * de
mutex/InitializeCriticalSection(&Gl.LockSct) ; Gl.Ilente = RECTIFIENT ; }} LuaLockFinal(lua_State vide * L)/* non appelé par Lua. */{/* détruisez un mutex. */si (Gl.Ilente)
{DeleteCriticalSection(&Gl.LockSct) ; Gl.Ilente = FAUX ;
}} LuaLock(lua_State vide * L) {/* attente la commande du * de mutex/EnterCriticalSection(&Gl.LockSct) ; } LuaUnlock(lua_State vide * L) {/* contrôle de la diffusion du * de
mutex/LeaveCriticalSection(&Gl.LockSct) ; }
Ces deux dossiers n'ont pas besoin de résider dans l'arbre de distribution de Lua, mais ils doivent être accessibles pendant la construction. En plus, vous devrez
définir LUA_USER_H de sorte que votre incluiez le dossier soit employé par Lua. Les citations doivent faire partie de la définition, de sorte qu'une expression quelque chose aiment
devra être transporté au compilateur. En outre, vous pouvez devoir prolonger le chemin d'inclusion de sorte que le compilateur puisse trouver votre dossier.
Fermeture par l'application
Lua empêche ses structures de données internes de devenir corrompues au moyen des fonctions de fermeture. Il appartient à l'application pour empêcher des problèmes avec les structures de données exposées, s'ils sont globaux ou des upvalues. Un mutex peut être employé pour coordonner l'utilisation de ressource employant des fonctions comme celles montrent en haut. Cependant, soyez sûr d'employer un mutex différent que celui employé par Lua afin d'éviter des impasses potentielles.
En concevant des applications multi-filetées, il est utile de prêter une attention particulière à où chaque fil attend. Rendiez-vous toujours compte que des opérations sans surveillance peuvent être interrompues. Si n'importe quel autre fil pourrait être compromis par l'état dans lequel une interruption se produit, une certaine forme d'exclusion mutuelle s'appelle pour.
Mutex et multitraitement globaux
La méthode ci-dessus pour mettre en application le filetage dans Lua employant un mutex global est inefficace sur des systèmes de multiprocesseur. Car un fil tient le mutex global, d'autres fils l'attendent. De ce fait seulement un fil de Lua peut fonctionner à la fois, indépendamment du nombre de processeurs dans le système.
Sur quelques systèmes il pourrait être nécessaire de rapporter le fil après avoir ouvert le mutex, afin d'empêcher le même fil de le fermer à clef encore, au cas où il y aurait d'autres qui attendent là-dessus. Ceci se produit au moins sur Linux en utilisant Boost.Threads. Le dépassement luai_threadyield (qui par des appels de
défaut lua_unlock, suivis immédiatement près lua_lock) pour rapporter le fil inbetween la serrure et l'ouvrir est probablement une bonne idée. Cependant, le luai_threadyield s'appelle par le macro de dojump dans la machine virtuelle, par conséquent un rendement à chaque appel de luai_threadyield pourrait considérablement dégrader l'exécution. L'alternative suivante pourrait être utile :
lua_State vide de luai_threadyield(struct * L) {count=0 interne statique ; y=false de bool ; si (compte -- <=0) {y=true ; count=30 ; } ; //valeurs d'essai
différentes au lieu du lua_unlock(L) 30. ; si (y) thread::yield() ; lua_lock(L) ; }
Table Faibles D'instruction
Il est utile de comprendre la collection d'ordures avant de lire ce cours d'instruction. Le GarbageCollectionTutorial fournit une introduction.
Le lien faible
Dans les langages de programmation tels que Lua qui utilisent la collection d'ordures, une référence à un objet serait faible si elle n'empêche pas la collection de l'objet. Les
références faibles sont utiles pour déterminer quand un objet a été rassemblé et pour cacher objectent sans empêcher leur collection.
Plutôt que fournissez une interface à différentes références faibles, Lua fournit une construction de plus haut niveau appelée une table faible. Dans une table faible les clefs et/ou les valeurs sont des références faibles. Si une clef ou une valeur d'une telle table est rassemblée, cette entrée de la table sera enlevée.
Voici un complet, bien que très arrangé, exemple d'une table faible dans l'action : t = {} setmetatable(t, {mode de __ = 'v '}) font someval local = {} t['foo '] = collectgarbage() someval d'extrémité pour k,
v dans t font le print(k, v) extrémité
Essayez cet exemple avec et sans collectgarbage() appel a commenté dehors. Avec l'appel, le programme n'imprimera rien, car la valeur de la seule entrée de table sera rassemblée.
Une table faible est créée en plaçant son metatable à un metatable qui a __mode un champ. Dans l'exemple ci-dessus nous permettons des valeurs faibles avec v (est k de même pour des clefs). Le but de créer la valeur d'essai someval comme variable locale dans do un bloc est de sorte que nous puissions forcer la collection d'ordures de la valeur plus tard avec un appel à collectgarbage. Notez cela qui emploie une coquille telle qu'une corde ou le nombre pour someval n'aurait pas fonctionné, car les coquilles ne sont jamais des ordures rassemblées.
Notez qu'une fois qu'une table a été employée car un metatable alors il n'est pas légal pour changer le champ __mode des metatable (pour les restrictions exactes voir la section 2.9.2 du manuel de référence de Lua 5.0 -
http://www.lua.org/manual/5.0/manual.html#2.9.2). En d'autres termes le code suivant, qui essaye de changer une table en table faible en changeant le champ de
ses __modemetatable, est erroné :
getmetatable(t).__mode = 'v '
Une table doit avoir son
__modechamp défini avant qu'elle soit employée en
tant que metatable. Par conséquent le modèle suivant, qui crée une table
vide et puis lui donne immédiatement un metatable, est correct :
weaktable local = setmetatable({}, {_ _ mode="k"})
Des tables faibles sont souvent employées dans les situations où vous souhaitez annoter des valeurs sans les changer. Par exemple, vous pourriez vouloir donner à des objets un nom qui pourrait être employé quand ils ont été imprimés. Dans ce cas-ci, vous ne voudriez pas le fait qu'un objet ait été appelé pour l'empêcher d'être des ordures rassemblées, ainsi vous voudriez employer une table avec des clefs faibles (les objets) :
les noms régionaux = le setmetatable({}, {_ _ mode =
"k"}) -- avec l'exemple ci-dessous, ce serait un name(obj de fonction
de fonction, un streptocoque locaux) names[obj ] = l'extrémité de
retour d'obj de tostring(str) -- gardent le print(disponible d'impression de gens du pays de fonction originale d'impression _ = de
fonction d'impression...) pour I = 1, arg.n font le nom régional = le
names[arg[i ] ] si arg[i de nom puis ] = l'extrémité nommée de print(unpack(arg d'extrémité d'extrémité _))
Vous pourriez vouloir employer ceci pour corriger, en appelant automatiquement des variables globales. Vous pouvez faire ceci en ajoutant un metamethod simple (voir le MetamethodsTutorial) à la table de globals :
] = vrai, l'userdata = vrai, fil = rectifient, table = rectifient}
fonction globalsmeta:__newindex(k, v) si name(v de nameable_type[type(v) ] puis, k) extrémité rawset(art de l'auto-portrait, k, v)
setmetatable(_G d'extrémité, globalsmeta)
Note comment nous évitons de faire une série complexe if then elseif... de rapports en employant une table constante pour faire un contrôle simple sur le type de la valeur. Pour les lecteurs d'instruction avançés, le texte de la fonction de newindex de __ pourrait être écrit comme suit :
rawset(art de l'auto-portrait, k, (nameable_type[type(v) ] et name(v,