1

我有这个函数可以正确加载我的命名空间:

(defn load-module [module-name]
    (use module-name)
)

而我的“等效”宏不起作用:

(defmacro load-module-macro [module-name]
    `(
        (use '~module-name)
    )
)

我不明白这个问题。

此外,我想使用这个宏来加载配置中选择的模块。在我的 config.clj 中,我使用包含“保存数据”功能的记录器模块的命名空间定义了一个 var。然后我想在我的核心程序中加载指定的记录器。所以我可以选择直接在我的配置文件中使用的记录器(磁盘上的记录器,数据库中的记录器......)。这是最好的方法吗?

编辑 :

错误信息

IllegalArgumentException Don't know how to create ISeq from: java.lang.Character  clojure.lang.RT.seqFrom (RT.java:505)
4

2 回答 2

3

不,实际上您根本不想在代码中直接使用“使用”。Use 会修改调用它的整个命名空间,这可能会以难以预测的方式破坏您的代码。

相反,您应该做的是:实现一个日志接口(协议),编写一个“元构造函数”,将您在 config.clj 中设置的任何内容作为关键字调度。代码示例

    (defprotocol ILog
      (save-data [this msg] "Logs message in msg."))



    (defn create-file-log
      "Returns an object implementing ILog, opens and flushes java.io.File file."
      [file]
      (let [f ... ;; create file writer here
            ]
        (reify ILog
          (save-data [this msg] ;; Write code that writes data to file here
            ))))

     ;; create other implementations like database here or elsewhere

     (defn create-log
       "Creates a log of of the type passed in type-kw."
       [type-kw]
       (case type-kw
         :file (create-file-log "./app-log.txt")
         ;; other types
         ))

现在,您只需使用配置文件中设置的任何关键字调用 create-log,并将返回的对象传递给需要进行日志记录的函数。显然,您也可以将其定义为全局对象,但我不建议这样做。

最终,您不仅想在配置中为所需的日志记录方法设置关键字(type-kw),还想在文件名或数据库 uri 等其他参数中传递类似的内容

   {:log-method :file
     :data {:fname "app-log.txt"}}
    or
   {:log-method :db
     :data {:uri "....

...到您的 create-log 函数,该函数使用此结构来获取 reify 构造函数 create-file-log、create-db-log 等的参数。

编辑: 因为你不喜欢 switch 语句,这里是如何用多种方法做到这一点:

  (defmulti create-log :logging-method)
  (defmethod create-log :file
    [arg-map]
    (let [file (java.io.File. (:fname arg-map))]
      (if (.exists file)
        ... 

然后,您只需在 config.clj 中有一个条目

  {...
   :log {:logging-method :file
         :fname "./log-file.txt"}}

要创建一个新的日志记录类型,您现在所要做的就是想象一个像上面那样的参数映射和一个用于 create-log 的构造函数方法。

于 2013-07-24T09:41:45.453 回答
1

我认为您也可以为此使用多种方法。这是 clojure 的另一种多态性策略,可能适用于您的用例,因为您只希望实现一个方法 ( save-data)。

;; set up a config map
(def config {:logger :db-logger)

;; set up the dispatch function to read the logger from the config map
(defmulti save-data (fn [] (:logger config))

;; define methods as required - database logging
(defmethod save-data :db-logger []
   (println "Save to database"))

;; some other logging  - can be in another file
(defmethod save-data :other-logger []
   (println "Save to other thing"))

注意:我对 Clojure 还是很陌生 - 所以我不确定这是否是使用多方法的“正确”方式。我看到的大多数示例都是在参数类型上调度的,而不是在配置设置上。如果我有错误的想法,请任何专家纠正我。

于 2013-07-24T10:21:19.853 回答