【问题标题】:Format output string depending on the data type根据数据类型格式化输出字符串
【发布时间】:2012-01-28 21:50:58
【问题描述】:

我正在编写一个 clojure 函数来将各种数据类型格式化为字符串。

我的幼稚解决方案:

(defn p [d]
       (cond
        (vector? d) (str "vector: " d)
        (list? d) (str "list: " d)))

#'user/p
user> (p [1 2 3])
"vector: [1 2 3]"
user> (p '(1 2 3))
"list: (1 2 3)"

我以前没有使用过多重方法。我这是一个很好的用途,还是有另一种方法可以避免使用 cond 的臭味?

【问题讨论】:

    标签: clojure


    【解决方案1】:

    按照@rodnaph 的建议,我会去定义格式协议并将其扩展为您需要的类型:

    (defprotocol Format
      (fmt [this]))
    
    (extend-protocol Format
      clojure.lang.IPersistentVector
        (fmt [this] (str "vector:" this))
      clojure.lang.IPersistentList
        (fmt [this] (str "list:" this)))
    

    但是我不知道哪个会有更好的性能,多方法或协议扩展。

    多方法定义可能如下所示:

    (defmulti fmt class)
    
    (defmethod fmt 
      clojure.lang.IPersistentVector [this]
        (str "vector:" this))
    (defmethod fmt 
      clojure.lang.IPersistentList [this]
        (str "list:" this))
    

    编辑:您可能想查看this question about protocols vs multimethods,因为两者的常见用例都得到了很好的解释。根据该信息,最好在您的场景中使用协议。

    【讨论】:

    • 感谢您展示如何做到这两种方式。我喜欢这里多方法的简单性。此时我可能只需要根据它是 seq 还是 string 或其他任何东西来更改格式,所以我可以避免对接口进行硬编码。
    【解决方案2】:

    (我是菜鸟,但是)看起来协议最适合这个:

    http://clojure.org/protocols

    然后,您可以为想要支持的每种数据类型定义不同的格式化实现。

    【讨论】:

      【解决方案3】:

      我确定您的问题显示了与您真正需要完成的任务相关的简化案例。对于一般解决方案,我同意协议是一种不错的方法。

      您询问了多方法,但您遇到的麻烦是调度函数。 defmulti 采用一个调度函数,该函数将在实际函数的参数上调用。调度函数必须返回一个值,然后可以使用该值来选择将调用哪个方法实现。

      问题是,你派什么来的?要区分集合类型,您最终会得到这样的结果:

      (defmulti stringify class)
      (defmethod stringify clojure.lang.PersistentVector [v] ...)
      (defmethod stringify clojure.lang.PersistentArrayMap [m] ...)
      ;;; More dispatching on concrete class names
      

      好吧,一旦您在代码中看到特定的 clojure.lang 类名,各种警钟都应该响起。这些太具体了……如果 Clojure 核心库发生更改,它们会中断,它们不会与 Java 互操作非常干净,它们不涵盖碰巧实现 Seqable 的用户定义类型……简而言之,它们是抽象的分解。

      任何时候,无论是来自 Clojure、Java 还是 3rd 方库,您都想通过类名进行分派,您应该始终改为使用扩展类型。

      【讨论】:

      • 为了我自己的学习 - 您是否有理由拒绝 Clojure 内置并记录在 clojure.org/multimethods 上的临时层次结构系统? (您没有提及它,并且似乎假设在具体类上进行调度,这似乎正在将 Java 读回 Clojure。)
      • 最初的问题是对数据结构使用文字。如果有办法在 {} 和 [] 之上构建临时层次结构,我不知道。我指出使用多方法必然会引入 Clojure 数据结构下的实现类(用 Java 编写)。这就是为什么我喜欢为此使用多方法。
      猜你喜欢
      • 2014-03-08
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多