Comment puis-je faire setf sur les accesseurs d'une structure lors de l'utilisation d'un stagiaire

StackOverflow https://stackoverflow.com/questions/3641509

  •  30-09-2019
  •  | 
  •  

Question

Je voudrais setf différents champs d'une structure en fonction d'une certaine variable.J'ai décidé d'utiliser l'approche suivante :

Générez une chaîne avec le nom de l'accesseur du champ :

(setq my-string (format nil "STRUCT-ESTADISTICAS-NUM-~S" x))

puis utilisez stagiaire avec funcall :

(funcall (intern my-string) *estadisticas*)

Cet appel renvoie la valeur correcte du champ de la structure, mais si j'essaye setf pour modifier cette valeur, il se plaint en disant :

(setf (funcall(intern my-string) *estadisticas*) 0)
Error: `(SETF FUNCALL)' is not fbound

Je peux comprendre pourquoi cela ne fonctionne pas, mais je ne trouve pas de moyen de modifier les champs de la structure.Une idée?Merci.

Était-ce utile?

La solution

Vous voulez appeler une fonction d'auteur de la struct par son nom, et le nom de l'écrivain est la liste (setf accessor-name); si

(funcall (fdefinition (list 'setf (intern my-string))) 0 estadisticas)

Edit:

Ne pas voir le reste de votre code, il est difficile de comprendre ce qui a mal tourné. Sur SBCL cela fonctionne pour moi:

(defstruct point x y)
(let ((point (make-point :x 1 :y 2)))
  (funcall (fdefinition (list 'setf (intern "POINT-X"))) 10 point)
  point)

Les évalue ci-dessus à

#S(POINT :X 10 :Y 2),

comme prévu.

Autres conseils

Motivation:

Les structures sont des installations de niveau relativement bas.La « vitesse » était un objectif de conception important.L'indirection via les fonctions d'écriture n'est pas prise en charge par la norme (comme je l'ai lu).Aujourd'hui, utilisez CLOS par défaut, à moins que l'on ait besoin d'une meilleure efficacité des structures (une lecture et une écriture plus rapides des slots avec des structures sont parfois possibles).

Premier style :

N'utilisez pas INTERN, utilisez FIND-SYMBOL.Spécifiez également le package, sinon FIND-SYMBOL utilisera la valeur d'exécution de *package* comme package

Deuxièmement - DÉFSTRUCTION

Si j'ai lu correctement la norme ANSI CL, ce n'est pas que DEFSTRUCT crée des fonctions d'écriture pour les emplacements comme le fait DEFCLASS.

CL-USER 24 > (defstruct foo bar baz)
FOO

CL-USER 25 > #'(setf foo-bar)

Error: Undefined function (SETF FOO-BAR) in form (FUNCTION (SETF FOO-BAR)).

Ainsi, construire un tel nom (SETF FOO-BAR) et essayer de trouver une fonction pour cela échouera, car aucune fonction de ce type n'est définie par DEFSTRUCT.

Cela fonctionne dans le code utilisateur (setf (foo-bar some-struct) 42), est basé sur les extensions SETF définies fournies par DEFSTRUCT, mais pas sur les fonctions d'accès SETF définies.

Certaines implémentations de Common Lisp peuvent fournir des fonctions d'écriture en tant qu'extension non standard d'ANSI CL.

Solutions possibles:

a) utilisez les classes CLOS, DEFCLASS fait ce que vous voulez

b) écrivez vous-même les fonctions d'écriture

(defun (setf foo-bar) (new-value struct)
   (setf (foo-bar struct) new-value))

Maintenant:

(funcall (fdefinition '(setf foo-bar)) 300 *foo*)

Ci-dessus fonctionne alors.

c) (SETF SLOT-VALUE) - une autre fonctionnalité non standard de certaines implémentations.

Dans certaines implémentations de Common Lisp, cela fonctionne non seulement pour les classes CLOS, mais aussi pour les structures :

(setf (slot-value some-struct 'bar) 42)

Je ne sais pas si Allegro CL prend en charge cela, mais ce serait facile à découvrir.

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