如何在生成类的Hy宏中实现通用参数解析以适配复杂入参结构
Hy defrecord宏通用化改造方案
核心问题是原实现硬编码按固定步长提取参数名,无法识别Hy参数列表中的特殊标记(如&optional/&kwonly)、带默认值的参数写法,我们通过新增编译期参数解析逻辑解决该问题。
步骤1:新增编译期参数解析辅助函数
首先在eval-and-compile块中新增通用参数解析函数,可兼容所有Hy函数参数语法:
(eval-and-compile (defn parse-params [param-list] (setv res []) (for [item param-list] ;; 跳过参数修饰符关键字 (if (and (symbol? item) (.startswith (str item) "&")) (continue) (do (setv param-name (cond ;; 处理带类型注解的参数:^(of T) name (and (instance? hy.Expression item) (= (str (first item)) "^")) (nth item 2) ;; 处理带默认值的参数:[name default] (instance? list item) (first item) ;; 普通无注解参数 True item)) (.append res param-name)))) res) ;; 保留原有的defproperty函数 (defn defproperty [attribute &optional docstring &rest body] `(with-decorator property (defn ~attribute [self] ~docstring (do ~@body) (return (getattr self (+ "__" (str '~attribute) "__")))))))
步骤2:改造defrecord宏
替换原硬切参数列表的逻辑,改用parse-params提取属性名,同时优化初始化赋值逻辑,去掉运行时eval避免安全和性能问题:
(defmacro/g! defrecord [recname inherits properties &optional docstring &rest body] ;; 用通用解析函数提取所有属性名 (setv g!properties% (parse-params properties)) `(defclass ~recname [~@inherits] ~docstring (defn __init__ [self ~@properties] ;; 宏展开时生成静态赋值语句,替代运行时循环+eval ~@(lfor prop% g!properties% `(setattr self (+ "__" (str '~prop%) "__") ~prop%))) ;; 生成所有属性的getter ~@(lfor prop% g!properties% `(defproperty ~prop%)) (do ~@body)))
兼容场景验证
改造后可支持原报错的复杂参数写法:
测试1:带可选参数
(defrecord record [] (^(of float) data ^(of int) x &optional ^(of str) doc)) (setv rec1 (record 2.0 3)) (setv rec2 (record 2.0 3 "abc")) (. rec2 doc) ;; 输出 "abc"
测试2:带仅限关键字参数+默认值
(defrecord record [] (^(of float) data ^(of int) x &kwonly ^(of str) [doc None])) (setv rec1 (record 2.0 3)) (setv rec2 (record 2.0 3 :doc "test")) (. rec1 doc) ;; 输出 None (. rec2 doc) ;; 输出 "test"
内容的提问来源于stack exchange,提问作者pacificprince
相关产品推荐
相关产品推荐

