通过List或Seq上的数字索引进行Clojure关联解构:意外结果

Dav*_*fer 3 clojure

Clojure的Associative Destructuring允许人们通过数字索引来解构vector(也许是seqlist)。

这种模式是不是在clojure.org提到,到目前为止,但中提到的Clojure的喜悦,第2版。迈克尔·福格斯(Michael Fogus),克里斯·豪斯(Chris Houser),2014年5月,第14页。59.这种方法出现在“关联解构”一节中-错误地是因为这种基于索引的解构只是“关联解构”的特例,在上述书中被称为“带地图的解构”。

无论如何,结果是意外的(Clojure 1.10.0):

在所有情况下,都提取索引0和3处的值。

这些工作按预期方式进行:

(let [{firstthing 0, lastthing 3} [1 2 3 4]] [firstthing lastthing])
;=> [1 4]

(let [{firstthing 0, lastthing 3} (vec '(1 2 3 4))] [firstthing lastthing])
;=> [1 4]
Run Code Online (Sandbox Code Playgroud)

但在清单上:

(let [{firstthing 0, lastthing 3} '(1 2 3 4)] [firstthing lastthing])
;=> [nil 4]
Run Code Online (Sandbox Code Playgroud)

为什么nil在位置0?

类似地:

(let [{firstthing 0, lastthing 3} (seq '(1 2 3 4))] [firstthing lastthing])
;=> [nil 4]
Run Code Online (Sandbox Code Playgroud)

但另一方面:

(let [{firstthing 0, lastthing 3} (vec (seq '(1 2 3 4)))] [firstthing lastthing])
;=> [1 4]
Run Code Online (Sandbox Code Playgroud)

这里发生了什么?

附录:

(let [{firstthing 0, lastthing 3} { 1 2 3 4 } ] [firstthing lastthing])
;=> [nil 4]
Run Code Online (Sandbox Code Playgroud)

...听起来是合理的,因为实际要被破坏的地图{1 2, 3 4}。因此,不是通过位置而是通过整数键(可以改变脚下的表达式的含义)进行查找的结果就是[nil 4]。是否将不是矢量的任何东西首先注入地图?

(let [{firstthing 10, lastthing 30} (seq '(10 2 30 4))] [firstthing lastthing])
;=> [2 4]
Run Code Online (Sandbox Code Playgroud)

看起来肯定像...

(let [{firstthing 10, lastthing 30} (seq '(10 2 30 ))] [firstthing lastthing])
; Execution error (IllegalArgumentException) at user/eval367 (REPL:1).
; No value supplied for key: 30
Run Code Online (Sandbox Code Playgroud)

哦耶。

cfr*_*ick 5

为什么在位置0处没有nil?

(let [{firstthing 0, lastthing 3} '(1 2 3 4)] [firstthing lastthing])
;=> [nil 4]
Run Code Online (Sandbox Code Playgroud)

如果您查看生成的代码let

(let [{firstthing 0, lastthing 3} '(1 2 3 4)] [firstthing lastthing])
;=> [nil 4]
Run Code Online (Sandbox Code Playgroud)

您会看到,如果出现seq?,它将转换为地图。所以:

user=> (macroexpand '(let [{firstthing 0, lastthing 3} '(1 2 3 4)] [firstthing lastthing]))
(let*
  [map__8012 (quote (1 2 3 4))
   map__8012 (if (clojure.core/seq? map__8012)
               (clojure.lang.PersistentHashMap/create (clojure.core/seq map__8012))
               map__8012)
   firstthing (clojure.core/get map__8012 0)
   lastthing (clojure.core/get map__8012 3)]
  [firstthing lastthing])

Run Code Online (Sandbox Code Playgroud)

因此,您获得nil密钥04密钥3