Вы можете просто merge
отобразить карту в записи, инициализированной с помощью nil
s:
(merge (MyRecord. nil nil nil) {:f1 "Huey" :f2 "Dewey"})
Обратите внимание, что записи могут содержать значения, хранящиеся под дополнительными ключами, в стиле карты.
Список полей записи можно получить с помощью отражения:
(defn static? [field]
(java.lang.reflect.Modifier/isStatic
(.getModifiers field)))
(defn get-record-field-names [record]
(->> record
.getDeclaredFields
(remove static?)
(map #(.getName %))
(remove #{"__meta" "__extmap"})))
Последняя функция возвращает последовательность строк:
user> (get-record-field-names MyRecord)
("f1" "f2" "f3")
__meta
и __extmap
поля, используемые записями Clojure для хранения метаданных и для поддержки функциональности карты, соответственно.
Вы можете написать что-то вроде
(defmacro empty-record [record]
(let [klass (Class/forName (name record))
field-count (count (get-record-field-names klass))]
`(new ~klass ~@(repeat field-count nil))))
и использовать его для создания пустых экземпляров классов записейвот так:
user> (empty-record user.MyRecord)
#:user.MyRecord{:f1 nil, :f2 nil, :f3 nil}
Полное имя здесь важно.Он будет работать до тех пор, пока класс записи будет объявлен ко времени компиляции любых empty-record
форм, ссылающихся на него.
Если empty-record
записано как функция, можно ожидать, что он ожидаетфактический класс в качестве аргумента (избегая «полностью квалифицированной» проблемы - вы можете назвать свой класс любым удобным для вас способом в данном контексте), но ценой выполнения отражения во время выполнения.