You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在生成类的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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.10.07 04:21:02