• Aucun résultat trouvé

[PDF] Cours avance sur Lua methodes et pratique | Formation informatique

N/A
N/A
Protected

Academic year: 2021

Partager "[PDF] Cours avance sur Lua methodes et pratique | Formation informatique"

Copied!
10
0
0

Texte intégral

(1)

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

(2)

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.

(3)

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

(4)

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

foo

et

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

foo

et sommes encore retournés sans erreur. Cependant, si nous

regardons le statut nous pouvons voir que nous avons sorti la

fonction

foo

et 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)

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

for

la 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

for

principale 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

for

la 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 :

(6)

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

(7)

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

(8)

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.

(9)

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

__mode

champ 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 :

(10)

] = 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,

Références

Documents relatifs

ةمدقم : اعقاو ضرف ثيح ولاكشأو وعاونأ فلاتخإ ىمع ةزيمم ةيعون ةمقن ينورتكللإا ملاعلإا ثدحأ دقل كش لاب زواجت دقف قوبسم ريغو ديازتم لكشب ومني هريثأت حبصأ و

L’archive ouverte pluridisciplinaire HAL, est destinée au dépôt et à la diffusion de documents scientifiques de niveau recherche, publiés ou non, émanant des

MAIN+ seeks to demonstrate the potential for process virtualization (existing or to be deployed processes) and suggests several tools to be chosen according of constraints

Le transfert de ce petit théâtre dans un service à thé, nous laisse penser que l’auteur fait un parallèle entre la scène de théâtre et la table, nous pourrions y voire

L’archive ouverte pluridisciplinaire HAL, est destinée au dépôt et à la diffusion de documents scientifiques de niveau recherche, publiés ou non, émanant des

In this paper, we explore the joint positions as gesture representation and we model the dynamics of the full skeleton as a trajectory using shape analysis on Riemannian manifolds

However, the fingerprint extraction from the PUF is contami- nated by measurement noise, creating a “dynamic” randomness source. Dynamic randomness creates measurement errors,

Face aux répercussions de l’invasion numérique des médias traditionnels, qui a parallèlement été à l’origine de la production de divers réseaux sociaux, nous devons faire