在Clojure中,您可以使用#
例如
#(+ % 1)
是一个接受参数并将其加1的函数。
但是我们还必须对正则表达式使用#
例如
(clojure.string/split "hi, buddy" #",")
这两个#
是否相关?
答案 0 :(得分:7)
还有集合#{}
,完全限定的类名构造函数#my.klass_or_type_or_record[:a :b :c]
,实例#inst "yyyy-mm-ddThh:mm:ss.fff+hh:mm"
and some others。
在以下情况下它们是相关的:#
启动clojure reader可以识别的序列,该序列将每个这样的实例分派给适当的读者。有一个guide对此进行了扩展
我认为存在此约定是为了将不同语法的数量减少到一种,从而简化读者。
答案 1 :(得分:3)
这两种用途没有(直接)关系。
在Clojure中,当您看到#
符号时,这是一个很大的线索,表明您正在与 Clojure Reader “说话”,而不是 Clojure编译器。在此处查看阅读器上的完整文档:https://clojure.org/reference/reader。
阅读器负责将纯文本从源文件转换为数据结构的集合。例如,比较Clojure和Java,我们有
; Clojure ; Java
"Hello" => new String( "Hello" )
和
[ "Goodbye" "cruel" "world!" ] ; Clojure vector of 3 strings
; Java ArrayList of 3 strings
var msg = new ArrayList<String>();
msg.add( "Goodbye" );
msg.add( "cruel" );
msg.add( "world!" );
类似地,即使在Clojure源代码中(在编译器将其转换为Java字节码之前),Reader也可以识别一些快捷方式,只是为了节省您的键入时间。即使在Clojure编译器启动之前,这些“阅读器宏”也将从您的“简短格式”源代码转换为“标准Clojure”。例如:
@my-atom => (deref my-atom) ; not using `#`
#'map => (var map)
#{ 1 2 3 } => (hash-set 1 2 3)
#_(launch-missiles 12.3 45.6) => `` ; i.e. "nothing"
#(+ 1 %) => (fn [x] (+ 1 x))
,依此类推。如@
或deref
运算符所示,并非所有阅读器宏都使用#
(哈希/磅/八字形)符号。请注意,即使在向量文字的情况下:
[ "Goodbye" "cruel" "world!" ]
阅读器创建的结果就像您键入的内容一样:
(vector "Goodbye" "cruel" "world!" )
答案 2 :(得分:0)
其他Lisps具有适当的可编程读取器,因此可以读取宏。 Clojure实际上没有可编程的读取器-用户无法轻松添加新的读取宏-但是Clojure系统确实在内部使用读取宏。 #
读取宏是dispatch宏,#
之后的字符是另一个读取宏表的键。
是的,#
确实意味着什么;但是它是如此的深刻和怪异,以至于您真的不需要知道这一点。
答案 3 :(得分:-1)
这两个
#
有关系吗?
不,不是。 #
文字的使用方式有所不同。您已经提到了其中的一些:这些是匿名函数和正则表达式模式。这是更多情况:
在表达式前加上#_
只会从编译器中删除它,因为它从未被写入过。例如:#_(/ 0 0)
在阅读器级别将被忽略,因此不会出现任何异常。
标记基元以将其强制为复杂类型,例如#inst "2019-03-09"
将产生java.util.Date
类的实例。还有#uuid
和其他内置标签。您可以注册自己的。
标记普通地图以将其强制为类型地图,例如#project.models/User {:name "John" :age 42}
将产生一个声明为(defrecord User ...)
的地图。