Clojure 中 -toString 和 .toString 的区别

3

《gen-class的解析和使用方法》中对:gen-class进行了介绍后,我使用leiningen获取了类文件。

  1. 运行leon new pinger创建一个项目。
  2. 进入src目录并创建一个名为some的文件夹,并在其中创建一个Example.clj文件。
  3. project.clj文件中添加:aot [some.Example](或:aot :all)。

Example.clj内容如下:

(ns some.Example
  (:gen-class))

(defn -toString
  [this]
  "Hello, World!")

我执行了lein compile命令,以获取位于target目录中的类。

接着,我使用lein repl命令来执行这段代码。

(-toString (some.Example.)) ; should return "Hello, World!"

然而,我收到了这个错误信息。
CompilerException java.lang.RuntimeException: Unable to resolve symbol: 
-toString in this context, compiling:(/private/var/folders/nw/dmb7jh3d2hq89296z2gnntqm0000gn/T/form-
init7145760420048735997.clj:1:1) 

.toString可以正常使用。

user=> (.toString (some.Example.))
"Hello, World!"

该网站解释说,-toString.toString应该得到相同的结果,但我只有使用.toString才能得到正确的结果。
在Clojure中,-toString.toString之间有什么区别?为什么在这个例子中-toString会引发错误?

我认为,由于-toString是一个普通的Clojure函数,除非您要求其命名空间并切换到它,或者使用其命名空间,否则它不会在您的repl中可见。 - noisesmith
1个回答

7
首先,一些术语:
1. (.toString (some.Example.))是对新构造的some.Example实例的toString方法的调用。
2. (-toString (some.Example.))是一个常规的Clojure函数调用,其中-toString是存储函数的Clojure Var的名称,(some.Example.)是它唯一的参数。 :gen-class会安排使-toString Var支持toString方法;也就是说,对some.Example实例的任何toString方法的调用都会导致对-toString的调用。因此,直接调用-toString等同于调用toString
但是,在通过引用存储它的Var来调用Clojure函数之前,您需要确保该Var所在的命名空间已加载(在这里没有问题,因为您能够构造some.Example的实例),然后通过其完全限定名称引用该Var,或者使用referuserequirealias将其缩短以便更容易地引用。
(some.Example/-toString ...)

(use '[some.Example :only [-toString]])
(-toString ...)

(require '[some.Example :refer [-toString]])
(-toString ...)

(require '[some.Example :as se])
(se/-toString ...)

;; refer and alias are typically not used directly

如果你在不先使用referuse或者require的情况下执行-toString,Clojure将尝试将符号-toString解析为当前命名空间(通常是REPL会话中的user;对于使用 defproject 表单的lein repl可能是:main命名空间)的变量。1

1 这个说法是针对REPL的。在源文件中,通常在ns表单中使用:use或者:require,语法与use/require相同,只是没有引用符号。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接