【问题标题】:Why argument list as ArraySeq?为什么参数列表为 ArraySeq?
【发布时间】:2011-11-20 22:19:34
【问题描述】:

考虑以下函数:

user> (defn first-args [& args]
            (args 0))
#'user/first-args
user> (first-args 1 2 3) ;=> clojure.lang.ArraySeq cannot be cast to clojure.lang.IFn

为什么参数列表是 clojure.lang.ArraySeq 而不是像 PersistentVector 这样更常见的东西?或者为什么ArraySeq 不实现IFn?性能原因?似乎你在做 Clojure 时必须了解一些事情的底层实现。欢迎赐教。

PS:这个问题不是关于“这是惯用的吗?”只是问为什么会这样。

【问题讨论】:

    标签: clojure arguments


    【解决方案1】:
    (defn first-args [& args]
      (first args))
    
    (apply first-args (range)) 
    ;=> 0
    

    您可以将函数应用于无限参数序列,仅根据需要使用项目。如果& args 被要求是一个向量(或任何比 ISeq 更具体的东西),这是不可能的。

    至于为什么 seqs 不可调用:它会鼓励以性能很差的方式使用它们。

    【讨论】:

      【解决方案2】:

      其他答案已经很好了,但只是想提出一个替代方案来达到同样的效果:

      (defn first-args [first-arg & others] 
        first-arg)
      
      (first-args 1 2 3)
      => 1
      

      即您可以在函数定义中显式命名第一个参数。

      【讨论】:

        【解决方案3】:

        您在第 2 行将 args 作为函数调用。实际上您想要的是:

        (defn first-args [& args]
          (first args))
        

        ArraySeq 实际上比 Vector 更“通用”,因为 Vector 继承了 ISeq。这就是为什么你不能在这里做(get args 0),这似乎是你想要调用的,因为它只适用于地图和向量,而不适用于任何 ISeq(如列表)。

        【讨论】:

        • 我想将向量用作函数,例如 ([1 2 3] 0) => 1。但后来我发现它不是正则向量。
        • PersistentVector 没有实现 ISeq;它是seqable,但不是seq。但即使是这样,我也看不出我们如何得出结论 ArraySeq 比向量更“常见”。
        猜你喜欢
        • 2020-07-18
        • 1970-01-01
        • 1970-01-01
        • 2019-07-04
        • 2020-09-17
        • 2014-03-04
        • 1970-01-01
        • 2015-04-16
        • 2012-09-22
        相关资源
        最近更新 更多