博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
namespace/symbol/:keyword/::keyword in Clojure
阅读量:5943 次
发布时间:2019-06-19

本文共 3516 字,大约阅读时间需要 11 分钟。

此文已由作者张佃鹏授权网易云社区发布。

欢迎访问,了解更多网易技术产品运营经验。

1.关键字(:keyword/::keyword):

  最近在学习使用clojure.spec(验证数据的格式)这个库,但在使用clojure.spec/def定义一个spec时,必须使用双冒号如下:

    ;;引入clojure.spec库    (use '[clojure.spec :as s])    ;;定义一个名为::spec-test的spec    (s/def ::spec-test even?)

  当时比较懵逼,不知道为什么会这样写,还以为是spec这个库特有的,就急着去使用该库了。后来才发现这也是一种关键字(::keyword),在某命名空间下的关键字(在其它语言c++中,::不是表示全局作用域吗??),我们可以使用namespace函数和name函数解释其如下:

    (namespace ::spec-test)    ;;=> "my-clj.core"    (name ::spec-test)    ;;=> "spec-test"

  原来::keyword就是关键字,只是表示的是当前命名空间下的关键字,主要为了解决关键字重名问题,也可以在当前命名空间下显式的定义namespace keyword:

    ;;定义一个带有命名空间的关键字,该命名空间可以随意指定,不一定是已经存在命名空间    (def ns-keyword :hello/A)    ;;=> #'my-clj.core/ns-keyword    ;;获取其namespace是"hello"    (namespace ns-keyword)    ;;=> "hello"    ;;获取其name是"A"    (name ns-keyword)    ;;=> "A"

  也就是说,有两种关键字,一种是全局的单冒号关键字,一种命名空间下的关键字,对于后者,可以使用::来定义关键字,表示是在当前命名空间下的关键字,也可以显式的写出命名空间的定义方法。

2.符号(symbol):

  符号是一个标志,在使用时不对其进行解释,前面需要加一个引号,阻止对其求值,如下:

    ;;定义一个变量a=3    (def a 3)    ;;=> #'my-clj.core/a    ;;直接使用a会对其进行求值    a    ;;=> 3    ;;如果使用symbol的方式则不对其进行求值,返回符号本身    'a    ;;=> a

  symbol与keyword一样,也分全局的symbol和命名空间下的symbol,如下:

    ;;全局的symbol    (namespace 'A)    ;;=> nil    ;;命名空间下的symbol,可以避免重名    (namespace 'hello/A)    ;;=> "hello"

  符号(symbol)主要用于创建列表和宏定义时,如下:

    ;;创建一个新的列表时,为了阻止其当作函数求值    '(1 2 3)    ;;=> (1 2 3)    ;;定义宏时,阻止对if当作函数计算    (defmacro unless [expr form]      (list 'if expr nil form))    ;;=> #'my-clj.core/unless

3.symbol/keyword/string/namespace之间的转换:

  在实际使用中,我们经常会遇到keyword和string之间的转换,尤其是如果将map中的key由string变为keyword的时候,会带来很多好处,比如我们使用的IDE中的keyword可以高亮显示,而且keyword还可以作为函数,更重要是的对map的结构会带来很多方便,所以掌握keyword和string之间的转换尤为重要。

  • 使用name函数将“关键字”转换为“字符串”(考虑namespace):

  首先可以使用name函数获取一个keyword的string形式:

    (name :A)    ;;=> "A"    ;;如果一个keyword中遇到"/",name函数会将第一个"/"前的字符串作为namespace,所以其返回的第一个"/"后的字符串    (name :hello/A)    ;;=> "A"

  但是有时候我们不希望把第一个斜杠"/"前的内容当作namespace,尤其是在将map转换为json格式的字符串时,有些keyword中带有“/”,但是它不是命名空间下的关键字,这时候如果使用name就会出错,但是大部分类似map2json的函数都会使用name来解释,所以会导致意想不到的错误发生。

  • 使用str函数将“关键字”转换为“字符串”(不考虑namespace):   鉴于以上情况,我们可以使用str函数将“关键字”转换为“字符串”,如下:

    ;;str函数返回的字符串会带有冒号    (str :hello/A)    ;;=> ":hello/A"    ;;在str函数的基础上调用.substring函数,则可以正确转换为我们想要的string    (.substring (str :hello/A) 1)    ;;=> "hello/A"

  • 使用namespace和name函数将“关键字”转换为“字符串”(不考虑namespace)   可以使用另外一种方法获取和str方法效果一样,就是使用namespace函数和name函数的组合,namespace函数可以获取一个“关键字”或“符号”的命名空间的字符串表示,如果无命名空间则返回nil:

    ;;namespace函数的用法:    (namespace :a)    ;;=> nil    (namespace :A/a)    ;;=> "A"    ;;它只会把第一个"/"前的字符串当作命名空间    (namespace :A/B/a)    ;;=> "A"    ;;使用namespace和name函数将keyword转换为string    (str (namespace :A/a) "/" (name :A/a))    ;;=> "A/a"

  特别注意的是,在clojurescript中,不要使用第三种方法,因为namespace函数在遇到多个斜杠时,会出现奇怪的问题,尽量使用第二种方法。

  • 使用keyword函数将“字符串”转换为“关键字”   将“字符串”转换为关键字,直接使用keyword函数便可,keyword函数可以接收一个参数或者两个参数,如果是两个参数的情况下,会把第一个参数当作命名空间,然后在两个参数中间加一个斜杠"/":

    (keyword "a")    ;;=> :a    ;;keyword可以接收有斜杠的字符串    (keyword "A/a")    ;;=> :A/a    ;;其实接收两个参数和接收一个参数本质上没有太大的区别,可以把两个参数用str合并后再调用keyword,可能只是为了突出强调namespace而已    (keyword "A" "a")    ;;=> :A/a    (keyword "A/B" "a")    ;;=> :A/B/a

  • 与“符号”(symbol)之间的相关转换:

    (1)其中symbol函数和keyword函数类似,可以将“字符串”转换为“符号”,同样也可以接收一个或者两个参数,如下:

    (symbol "a")    ;;=> a    ;;如果两个参数,第一个参数作为命名空间    (symbol "A" "a")    ;;=> A/a

   (2)“符号”也可以作为namespace函数和name函数的参数,用法和“关键字”作为参数类似,可以将一个“符号”转换为“字符串”,如下:

    (namespace 'hello/A)    ;;=> "hello"    (name 'hello/A)    ;;=> "A"    ;;无命名空间时,namespace总是返回nil    (namespace 'A)    ;;=> nil    (name 'A)    ;;=> "A"

参考文章:

更多网易技术、产品、运营经验分享请。

相关文章:

【推荐】 
【推荐】 
【推荐】 

转载地址:http://cswxx.baihongyu.com/

你可能感兴趣的文章
javaScript实现归并排序
查看>>
关于jsb中js与c++的相互调用
查看>>
GraphQL 01--- GraphQL 介绍及资源总结
查看>>
nginx配置访问密码,让用户输入用户名密码才能访问
查看>>
串结构练习——字符串匹配
查看>>
CF Round #426 (Div. 2) The Useless Toy 思维 水题
查看>>
UVA 122 Trees on the level 二叉树 广搜
查看>>
POJ-2251 Dungeon Master
查看>>
tortoisesvn的安装
查看>>
大S变"汪太"!与汪小菲注册结婚
查看>>
我是怎么使用最短路径算法解决动态联动问题的
查看>>
sublime Text 2 配置以及 Python环境搭建
查看>>
[2778]小明的花费预算 (二分查找)SDUT
查看>>
Runnable接口介绍(中文文档)
查看>>
URAL 1353 Milliard Vasya's Function DP
查看>>
速读《构建之法:现代软件工程》提问
查看>>
在iOS微信浏览器中自动播放HTML5 audio(音乐)的2种正确方式
查看>>
Android onclicklistener中使用外部类变量时为什么需要final修饰【转】
查看>>
Matlab2012a下配置LibSVM—3.18
查看>>
SpringBoot 搭建
查看>>