How to convert a keyword into a character suitable for accessing a slot?

I have a class with several slots. I also have a builder function to create objects of this class, so passing the next list '(:id "john" :name "John Doe" :age 42)to this function will create a new object with these slot values. I will use this function to create more than one object using a list of lists.

How can I convert from a type keyword :idto a slot name that I SLOT-VALUEcan use?

Thank.

+5
source share
4 answers

find-symbol symbol-name . defclass slot-value , :

(defclass person ()
  ((id :initarg :id)
   (name :initarg :name)
   (age :initarg :age)))

(slot-value (make-instance 'person :id "john" :name "John Doe" :age 42)
            (find-symbol (symbol-name :id)))

defclass slot-value , find-symbol , defclass:

(in-package #:common-lisp-user)

(defpackage #:foo
  (:use #:common-lisp)
  (:export #:person))

(defpackage #:bar
  (:use #:common-lisp #:foo))

(in-package #:foo)

(defclass person ()
  ((id :initarg :id)
   (name :initarg :name)
   (age :initarg :age)))

(in-package #:bar)

(slot-value (make-instance 'person :id "john" :name "John Doe" :age 42)
            (find-symbol (symbol-name :id) 'foo))

(find-symbol name &optional (package (sane-package)))

: STRING . , : INTERNAL,: EXTERNAL : INHERITED, , . , NIL.

 

(symbol-name symbol)

: SYMBOL .

+3

initargs , MAKE-INSTANCE APPLY:

(defclass person ()
  ((id   :initarg :id  )
   (name :initarg :name)
   (age  :initarg :age )))


CL-USER > (mapcar
           (lambda (initargs)
             (apply #'make-instance 'person initargs))
           '((:id "john" :name "John Doe" :age 42)
             (:id "mary" :name "Mary Doe" :age 42)))

(#<PERSON 402027AB7B> #<PERSON 402027AC33>)
+10

, , , , :

slot-value !

, :accessor :reader, :initarg:

(defclass foo ()
  ((bar :accessor foo-bar :initarg :bar)))

: getter setf foo-bar :bar to make-instance .

:

(make-instance 'foo :bar "quux")

, initargs ( ):

(let ((initargs (list :bar "quux"))) ; getting this from somewhere
  (apply #'make-instance 'foo initargs))

:

(foo-bar some-foo)

setf, :

(setf (foo-bar some-foo) "wobble")

:reader :accessor, . .

slot-valuevalid for special situations in the life of an object, for example, when playing with methods for initialize-instance. This is an advanced topic.

+1
source

My solution to this CL stupidity was:

(defun locate-symbol
       (inst kw)
  (let* ((slot-name (symbol-name kw))
         (slot-def (find slot-name
                         (clos:compute-slots (class-of inst))
                         :test #'(lambda (name sd)
                                   (string= name
                                            (symbol-name (clos:slot-definition-name sd)))))))
    (if slot-def
        (clos:slot-definition-name slot-def)
      (error "Can't find a slot definition named ~s." slot-name))))

(defun gets
       (self slot-name)
  "Get a value of a slot by its name (keyword)"
  (slot-value self (locate-symbol self slot-name)))

(defun sets!
       (self slot-name value)
  "Set a value of a slot by its name (keyword)"
  (setf (slot-value self (locate-symbol self slot-name))
        value))

So now you can do:

(defvar obj (make-instance '<some-class>))
(sets! obj :some-slot "some value")
(format t "-> ~a~%" (gets obj :some-slot))
-1
source

All Articles