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!
所有 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 实例的静态方法。
关于宏defn
vs defn-
,第二种形式只是“私有”功能的简写。长格式如下:
(defn ^:private foo [args] ...)
Run Code Online (Sandbox Code Playgroud)
但是,这只是向用户暗示不应使用这些功能。测试等可以轻松解决此弱的“私有”限制。由于麻烦,我从不使用所谓的“私有”功能(有时我会使用元数据^:no-doc
和名称foo-impl
来表示fn并非面向公众的API的一部分,图书馆用户应该忽略它们)。
在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-
。
归档时间: |
|
查看次数: |
141 次 |
最近记录: |