2024 Clojure状态调查!分享你的想法。

欢迎!有关如何使用这个功能,请参阅关于页面获取更多信息。

0
ClojureScript
两个命名空间


(ns my.ns)

(defrecord A [foo bar])

(defn make-a [foo bar]
  (A. foo bar))



(ns other.ns
  (:require [my.ns :refer (A)]))

(println (my.ns/A. 1 2) (my.ns/make-a 1 2))

(defrecord A [baz quux])

(println (my.ns/A. 1 2) (my.ns/make-a 1 2))


加载 {{other.ns}} 会产生输出


#my.ns.A{:foo 1, :bar 2} #my.ns.A{:foo 1, :bar 2}
#my.ns.A{:baz 1, :quux 2} #my.ns.A{:baz 1, :quux 2}


{{other.ns.A}} 的定义覆盖了 {{my.ns.A}}

4 答案

0

由:cemerick

这可能是 CLJS-1558 的重复?

0

由:mfikes

这个问题与 CLJS-1558 存在相似之处,因为编译器基本上允许你重新 {{def}} 引用的 Var。可能这两个问题都应该导致编译器错误,就像 Clojure 中的那样。

0
_由:mfikes_

我在确定应该发生的情况时有些纠结,核心问题在于 {{my.ns/A}} 是一个 Var 还是仅仅是一种类型。

在编译状态中,它在 {{:defs}} 下出现,但被标记为 {{:type true}}。换句话说,仅仅因为它在 {{:def}} 下面并不意味着它就是一个 Var。在 Clojure 中,尽管存在一个可以通过互操作访问的底层构造函数,但没有创建实际的 Var。(这一说法的证据是,{{(var A)}} 在 Clojure 中会失败,并且在 REPL 中使用 {{dir}} 时不会出现 Var——你只能看到相关的合成位置和映射工厂 Var。)

另一个证据表明“它不是一个 Var”的是 {{defrecord}} 返回的内容。{{defrecord}} 并不返回 Var(即使是 Clojure),而是返回一个符号(它等于自身,就像符号 {{java.lang.String}} 一样)。

如果你认为底层构造函数不是一个 Var,那么可能某些事情可以被清理(修复 ClojureScript 中的 {{dir}},也许还会让 {{var}} 在应用于类型时拒绝)。

如果你认为它不是一个 Var,那么你可能会认为 {{import}} 是合适的,而 {{require}} 则不是。受到 http://puredanger.github.io/tech.puredanger.com/2010/06/30/using-records-from-a-different-namespace-in-clojure/ 的启发,这个变化似乎可以正常工作


(ns my.ns)

(defrecord A [foo bar])



(ns other.ns
  (:require [my.ns])
  (:import (my.ns.A)))

(println (my.ns.A. 1 2) (my.ns/->A 1 2))

(defrecord A [baz quux])

(println (my.ns.A. 1 2) (my.ns/->A 1 2))

(println (A. 3 4) (->A 3 4))


可以得到以下结果


cljs.user=> (require 'other.ns)
#my.ns.A{:foo 1, :bar 2} #my.ns.A{:foo 1, :bar 2}
#my.ns.A{:foo 1, :bar 2} #my.ns.A{:foo 1, :bar 2}
#other.ns.A{:baz 3, :quux 4} #other.ns.A{:baz 3, :quux 4}
nil


我不喜欢的一点是,你必须写成 {{(:import (my.ns.A))}} 而不是 {{(:import (my.ns A))},但也许这只是一个小小的怪癖,如果采取“不是一个 Var”的方法,可能可以清理。
0
参考资料: https://clojure.atlassian.net/browse/CLJS-2421(由 cemerick 报告)
...