Что означает символ - (минус) перед именем функции в Clojure? - PullRequest
4 голосов
/ 25 октября 2019

Я не могу сообразить следующее. При определении основной функции в Clojure (на основе кода, сгенерированного Leinigen), перед именем функции main стоит символ -.

Я пошел в оригинальную документацию на clojure.com и обнаружил defn и defn- среди прочего, см. https://clojuredocs.org/search?q=defn. Я также искал в Google и нашел источник, который сказал, что - перед main указывает на то, что функция статическая (http://ben.vandgrift.com/2013/03/13/clojure-hello-world.html).

Действительно ли - означает, что функция статическая? Я не смог найти другие источники, которые подтвердили бы это. Также я могуиспользуйте (main) и (-main) при вызове основного метода без каких-либо проблем.

Учитывая следующий код ...

(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!"))

Я получаю следующий вывод ...

(main)
Hello, World!
=> nil
(-main)
Hello, World!
=> nil
Loading src/clojure_example/core.clj... done
(main)
Hello, World!
=> nil
(-main)
Hello, World!
=> nil

Я не заметил никакой разницы. Вывод одинаков для обеих функций. Любая помощь приветствуется!

Ответы [ 2 ]

5 голосов
/ 25 октября 2019

Во-первых, в стороне.

Что касается макросов defn против defn-, 2-я форма - это просто сокращение для «частных» функций. Полная форма выглядит следующим образом:

(defn ^:private foo [args] ...)

Тем не менее, это всего лишь подсказка для пользователя, что не следует использовать эти функции. Для тестирования и т. Д. Легко обойти это слабое «личное» ограничение. Из-за хлопот я никогда не использую так называемые «частные» функции (иногда я использую метаданные ^:no-doc и такие имена, как foo-impl, чтобы указать, что fn не является частью общедоступного API и должен игнорироваться пользователями библиотеки).


Функция "main" в программе Clojure

В Java программа всегда запускается с помощью вызова "главная »функция в выбранном классе

class Foo
  public static void main( String[] args ) {
    ...
  }
}

, а затем

> javac Foo.java   ; compile class Foo
> java Foo         ; run at entrypoint Foo.main()

Clojure выбирает имя начальной функции -main. Дефис в имени функции -main на самом деле не является особенным, за исключением того, что делает его необычным, поэтому он менее вероятно конфликтует с любой другой функцией в вашей кодовой базе. Вы можете увидеть это в определении функции clojure.main/main-opt.

Вы можете увидеть часть происхождения соглашения о гипене в документах для gen-class(прокрутите вниз, чтобы увидеть часть о :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    

, поэтому в такой программе:

(ns demo.core )

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

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

мы получаем нормальное поведение:

~/expr/demo > lein run

*** Running in main program ***

Однако мы могли бы вызвать программу другим способом:

> lein run -m demo.core/foo

*** Running in foo program ***

, чтобы сделать функцию foo «точкой входа». Мы также можем изменить настройку :main следующим образом:

:main ^:skip-aot demo.core/foo

и получить поведение:

~/expr/demo > lein run

*** Running in foo program ***

Итак, имея начальную функцию программы Clojure с именем -main является значением по умолчанию и требуется для большинства инструментов. Вы можете переопределить значение по умолчанию, если используете Leiningen, хотя это, вероятно, полезно только при тестировании и разработке.

Помните, что каждое пространство имен может иметь свою собственную функцию -main, поэтому вы можете легко изменить исходную функциюпросто путем изменения начального пространства имен, которое вызывается.

И, наконец, дефис в -main нас не связан с дефисом, используемым для псевдо-частных функций, определенных с помощью defn-.

4 голосов
/ 25 октября 2019

Все функции clojure являются «статическими» (отступление ниже). Размещение символа - в качестве первого символа в имени функции не влияет на поведение функции. Использование макроса defn- вместо defn делает функцию приватной. -main - это ~~ по соглашению ~~ имя главной точки входа для программы clojure. Если вы зададите ns в определении своего проекта в качестве "основного" пространства имен, среда выполнения clojure будет искать функцию с именем -mainи вызвать его.

Это не совсем "условно", теперь я думаю об этом. Как это не настраивается для стандартных инструментов. Это единственное имя, которое будет искать clojure.main.

https://clojure.org/reference/repl_and_main

На самом деле все функции clojure являются экземпляром объекта Java-функции AFunction с методом экземпляра invoke,Таким образом, они не статичны с точки зрения Java, но, находясь в сомнительной стране, я бы сказал, что они есть, поскольку у них нет экземпляра, который вы видите. Существует также особый случай gen-класса, где вы определяете класс java с помощью clojure. В этом случае вы можете пометить функции clojure как ^: static для сгенерированного Java-класса. Это создает статический метод в сгенерированном классе Java, который ссылается на экземпляр AFunction.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...