Clojure: определить, объявлена ли переменная
Как я могу проверить, была ли объявлена или назначена переменная (т.е. проверить, определено ли "а", когда я ожидаю, что программа выведет какой-то код как это (def a (create-a))?
И связанный --- как ответ на этот вопрос связан с проблемой разрешения символа (т.е. функции), который был объявлен? Clojure: определить, существует ли функция
Кажется, что определенная переменная должна быть проверена в том же смысле, что определенная функция есть, но я нахожу, что решение для определения, существует ли функция, недостаточно для определения того, существует ли какая-либо переменная.
В некотором контексте: я пишу модульные тесты для проекта мультидетектора и хочу, чтобы были определены тестовые данные и методы в разных классах. Поскольку нет хорошей поддержки IDE для clojure, мне кажется, что, учитывая ее свободную структуру, хорошо протестировать имена методов и имена переменных, прежде чем тестировать их выходы/содержимое.
Ответы
Ответ 1
Вы можете использовать resolve, чтобы увидеть, была ли переменная привязана/определена:
(resolve 'meaning)
nil
(def meaning 42)
#'user/meaning
(resolve 'meaning)
#'user/meaning
или вы можете логически проверить его, если вам нужно true/false:
(boolean (resolve 'meaning))
true
Ответ 2
Один из способов сделать это - использовать ns-resolve, например:
user=> (def a "hello a")
user=> (ns-resolve *ns* 'a)
#'user/a
user=> (ns-resolve *ns* 'b)
;nil ; This assumes b hasn't been defined before...
Обратите внимание, что если вы используете пространство имен для проверки выбранного символа, то то, что вы передаете в качестве первого аргумента (*ns*
в приведенном выше примере), не имеет значения:
user=> (ns-resolve 'user 'a)
#'user/a
user=> (ns-resolve 'other 'a)
nil
user=> (ns-resolve 'other 'user/a)
#'user/a
Функция resolve, упомянутая @tolitius, на самом деле является сокращением для ns-resolve
, где аргумент пространства имен всегда оценивается как ns, в зависимости от использование может быть более удобным.
Ответ 3
Как говорили другие, resolve
вернет var для символа, если есть один определенный или nil. Кроме того, вы можете проверить, имеет ли значение var значение, связанное с ним, используя bound?
.
user=> (resolve 'foo)
nil
user=> (def foo)
#'user/foo
user=> (resolve 'foo)
#'user/foo
user=> (bound? #'foo)
false
user=> (def foo 5)
#'user/foo
user=> (bound? #'foo)
true
Ответ 4
Поскольку нет хорошей поддержки IDE для clojure, мне кажется, что, учитывая его свободную структуру, хорошо протестировать имена методов и существование переменных имен перед тестированием их выходов/содержимого.
Это орехи. Вы действительно хотите, чтобы тест сказал: "Ой! Ты забыл определить foobar
!" вместо того, чтобы просто запускать foobar
и видеть сообщение clojure "Невозможно разрешить символ"?
Что вы получаете от этого? Вы теряете стек, который может быть полезен, если, например, тесту передается неправильное имя функции каким-либо другим кодом. Гораздо лучше знать, что строка неправильно написана foobar, чем искать через весь тестовый пространство имен.