What does the - (minus) symbol in front of function name within Clojure mean?

M. *_*out 4 clojure

I can't get my head around the following. When defining the main function in Clojure (based on code generated by Leinigen), there's an - symbol in front of the function name main.

I went to the original documentation on clojure.com and found defn and defn- among other things, see https://clojuredocs.org/search?q=defn. I also searched on Google and found a source that said that the - in front of main indicated that the function was static (http://ben.vandgrift.com/2013/03/13/clojure-hello-world.html).

Does the - truely mean that the function is static? I couldn't find any other sources that confirmed that. Also I can use both (main) and (-main) when calling the main method without any problem.

Given the following code...

(defn -main
  "I don't do a whole lot ... yet."
  [& args]
  (println "Hello, World!"))

(defn main
  "I don't do a whole lot ... yet."
  [& args]
  (println "Hello, World!"))
Run Code Online (Sandbox Code Playgroud)

I get the following output...

(main)
Hello, World!
=> nil
(-main)
Hello, World!
=> nil
Loading src/clojure_example/core.clj... done
(main)
Hello, World!
=> nil
(-main)
Hello, World!
=> nil
Run Code Online (Sandbox Code Playgroud)

I noticed no difference. Output is the same for both functions. Any help is appreciated!

bfa*_*bry 8

所有 clojure 函数都是“静态的”(下面的题外话)。将 - 作为函数名称中的第一个字符不会对函数的行为产生任何影响。使用defn-宏而不是defn使函数私有。-main是~~按照约定~~ clojure 程序的主入口点的名称,如果您在项目定义中指定一个 ns 作为“main”命名空间,则 clojure 运行时将查找命名的函数-main并调用它。

现在我想这并不是真正的“按惯例”。因为它对于标准工具是不可配置的。这是 clojure.main 将寻找的唯一名称。

https://clojure.org/reference/repl_and_main

所有的clojure函数实际上都是一个java对象AFunction的实例,带有一个实例方法invoke。因此,从 Java 的角度来看,它们不是静态的,但是在 clojure 领域中,我会说它们是静态的,因为它们没有您看到的实例。还有 gen-class 的特殊情况,您可以使用 clojure 定义一个 java 类。在这种情况下,您可以将 clojure 函数标记为 ^:static 用于生成的 java 类。这将在生成的 java 类中创建一个引用 AFunction 实例的静态方法。


Ala*_*son 5

首先,放在一边。

关于宏defnvs defn-,第二种形式只是“私有”功能的简写。长格式如下:

(defn ^:private foo [args] ...)
Run Code Online (Sandbox Code Playgroud)

但是,这只是向用户暗示不应使用这些功能。测试等可以轻松解决此弱的“私有”限制。由于麻烦,我从不使用所谓的“私有”功能(有时我会使用元数据^:no-doc和名称foo-impl来表示fn并非面向公众的API的一部分,图书馆用户应该忽略它们)。


Clojure程序中的“主要”功能

在Java中,总是通过在选定的类中调用“ main”函数来启动程序

class Foo
  public static void main( String[] args ) {
    ...
  }
}
Run Code Online (Sandbox Code Playgroud)

然后

> javac Foo.java   ; compile class Foo
> java Foo         ; run at entrypoint Foo.main()
Run Code Online (Sandbox Code Playgroud)

Clojure选择命名初始功能-main。函数名称中的连字符-main不是很特殊,除了它使名称不寻常之外,因此它不太可能与代码库中的任何其他函数发生冲突。您可以在函数的定义看到这一点clojure.main/main-opt

您可以在的文档中查看gen-class hypen约定的起源的一部分(向下滚动以查看有关的部分:prefix)。请注意,如果gen-class用于Java互操作,则可以使用连字符进行更改。

使用Clojure Deps和CLI工具,该名称-main被假定为程序的起点。


如果您使用的是Leiningen,它会更加灵活,并且允许您覆盖-main程序的入口点。

在Leiningen项目中,如下所示的条目指示您键入时从哪里开始lein run

; assumes a `-main` function exists in the namespace `demo.core` 
:main ^:skip-aot demo.core    
Run Code Online (Sandbox Code Playgroud)

所以在这样的程序中:

(ns demo.core )

(defn foo [& args]
  (newline)
  (println "*** Running in foo program ***")
  (newline))

(defn -main [& args]
  (newline)
  (println "*** Running in main program ***")
  (newline))
Run Code Online (Sandbox Code Playgroud)

我们得到正常的行为:

~/expr/demo > lein run

*** Running in main program ***
Run Code Online (Sandbox Code Playgroud)

但是,我们可以用另一种方式调用程序:

> lein run -m demo.core/foo

*** Running in foo program ***
Run Code Online (Sandbox Code Playgroud)

使foo功能成为“入口点”。我们还可以:main像这样更改设置:

:main ^:skip-aot demo.core/foo
Run Code Online (Sandbox Code Playgroud)

并得到行为:

~/expr/demo > lein run

*** Running in foo program ***
Run Code Online (Sandbox Code Playgroud)

因此,-main默认情况下,具有名为Clojure程序的初始功能是大多数工具所必需的。如果使用Leiningen,则可以覆盖默认值,尽管这可能仅对测试和开发有用。

请记住,每个名称空间都可以有其自己的-main功能,因此您只需更改调用的初始名称空间就可以轻松更改初始功能。

最后,-main我们中的连字符与用于通过定义的伪私有函数的连字符无关defn-