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。 (支持这一说法的证据是在 Clojure 中 {{(var A)}} 会失败,如果你在 REPL 中使用 {{dir}},将不会出现任何 Var——你只能看到相关的自生成位置和映射工厂 Vars。

"它不是一个 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
by
参考: https://clojure.atlassian.net/browse/CLJS-2421 (由 cemerick 报告)
...