【问题标题】:what advantage is there to use 'get' instead to access a map使用“get”来访问地图有什么好处
【发布时间】:2013-01-23 20:29:33
【问题描述】:

跟进这个问题:Idiomatic clojure map lookup by keyword

可以通过多种方式使用 clojure 访问地图。

(def m {:a 1}

(get m :a) ;; => 1
(:a m) ;; => 1
(m :a) ;; => 1

我知道我主要使用第二种形式,有时使用第三种,很少使用第一种。使用它们的优点(速度/可组合性)是什么?

【问题讨论】:

  • 查看您链接的问题的答案。 get 唯一想到的另一件事是 3-arity 版本(未找到获取映射键),您可以在其中(双关语)指定默认值。
  • @A.Webb 您可以为所有三种用途指定默认值:(:k m default)(m :k default) 都可以,当然前提是 m 不为零。
  • @amalloy 啊,很酷,谢谢你指出这一点!

标签: clojure


【解决方案1】:

get 在 map 可以是 nil 或 not-a-map 并且键可以是不可调用的东西(即不是关键字)时很有用

(def m nil)
(def k "some-key")

(m k)  =>  NullPointerException
(k m)  =>  ClassCastException java.lang.String cannot be cast to clojure.lang.IFn

(get m k)  =>  nil
(get m :foo :default)  =>  :default

【讨论】:

    【解决方案2】:

    the clojure web page 我们看到

    Maps 实现 IFn,对于一个参数(一个键)的调用() 可选的第二个参数(默认值),即映射是 他们的钥匙。 nil 键和值都可以。

    有时深入了解 Clojure 的内部结构会很有帮助。如果您查看 invoke 在地图中的样子,您会看到:

    https://github.com/clojure/clojure/blob/master/src/jvm/clojure/lang/APersistentMap.java#L196

    它显然调用了地图的valAt 方法。

    如果您查看使用地图调用 get 函数时的作用,这是对 clojure.lang.RT.get 的调用,这实际上归结为对地图的相同调用 valAt(地图实现 ILookUp 是因为他们是Associatives):

    https://github.com/clojure/clojure/blob/master/src/jvm/clojure/lang/RT.java#L634.

    对于使用键和未找到值调用的映射也是如此。那么,有什么优势呢?由于这两种方式归结为几乎相同,性能方面我不会说什么。这只是语法上的方便。

    【讨论】:

      【解决方案3】:

      您可以将get 传递给partial 等来构建HOF 来处理您的数据,尽管它不会经常出现。

      user=> (def data {"a" 1 :b 2})
      #'user/data
      user=> (map (partial get data) (keys data))
      (1 2)
      

      当数据有字符串作为键时,我经常使用第三种形式

      【讨论】:

      • 这并没有真正解决问题。您可以很容易地通过(map data (keys data)) 获得等效的(vals data)
      • 重点是 get 可以与函数转换函数组合,在数据映射可用之前产生一个数据旋转函数。此示例单独说明了这一点,但在实践中它与其他特定问题的约束相结合。
      【解决方案4】:

      我认为没有速度差异,即使是这种情况,这也是一个实现细节。

      我个人更喜欢第二个选项 (:a m),因为它有时会使代码看起来更容易一些。例如,我经常需要遍历一系列地图:

      (def foo '({:a 1} {:a 2} {:a 3}))
      

      如果我想过滤 :a 的所有值,我现在可以使用:

      (map :a foo)
      

      而不是

      (map #(get % :a) foo)
      

      (map #(% :a) foo)
      

      当然这是个人喜好问题。

      【讨论】:

        【解决方案5】:

        要添加到列表中,get 在使用线程宏-> 时也很有用,您需要通过非关键字的键访问

        (let [m {"a" :a}] (-> m (get "a")))

        【讨论】:

          【解决方案6】:

          使用关键字优先方法的一个优点是它是在映射为 nil 的情况下以宽容的行为访问值的最简洁方法。

          【讨论】:

            猜你喜欢
            • 2020-10-22
            • 2020-10-20
            • 2012-11-30
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 2012-11-28
            • 2010-09-21
            • 2011-04-28
            相关资源
            最近更新 更多