zoukankan      html  css  js  c++  java
  • Clojure的学习笔记(三)

    Clojure和Java

    Clojure的代码是被编译为java字节码而执行的,因此Clojure和Java代码的集成度相当高,这也是很多人学习Clojure的原因,因为跟Lisp这样的语言相比,它不仅仅具备强大的表达能力,同时也能尽可能的利用现有的‘智力遗产’。

    如何访问构造函数、方法和域

    Clojure中提供了new关键字来生成一个对象 (new classname),生成的对象可以用def语句绑定到某个变量之上,绑定之后便可以用 . 运算符来访问该对象的方法:

    (def rnd (new java.util.Random))
    
    (. rnd nextInt)
    -791474443
    

    对于方法调用的参数,则直接写在函数名后面就可以了:

    (. rnd nextInt 10)
    

    . 运算符不仅仅可以用在访问对象的方法,还可以用在访问对象的域、静态的或者非静态的都行。比如我们可以用(. Math PI)访问Math类下的静态变量PI

    需要记住的是,clojure的new方法的参数必须是相对PATH的完整的类名,比如上面例子的Random类。不过有一个包中的类是例外:java.lang。

    为了避免一直使用较长的类名字,我们通常会使用import方法: (import [& import-list]),这其中的import-list主要包括两个部分,前一部分表示包所在的路径,后一部分表示需要导入的类名字,比如:

    (import '(java.util Random Locale) '(java.text MessageFormat))
    

    这基本上就是Clojure调用Java的全部了。简单吧!

    语法糖衣

    大部分的java相关操作的语句都有一个简化版,比如new:

    (new Random) == (Random .)
    

    对于方位类中的静态元素,直接可以使用/,而不是.

    (. Math Pi) == Math/PI
    

    静态方法也可以用/来直接调用

    (. System currentTimeMills) == (System/currentTimeMills)
    

    我们甚至可以用更简单的方法来表述对象的函数调用或者域访问:

    (. rnd nextInt) = (.nextInt rnd)
    

    为了简化java中多个类不断调用,而如果写成这种前缀形式会显得比较丑陋。Clojure提供了 .. 宏

    (.getLocation (.getCodeSource (.getProtectionDomain (.getClass '(1 2)))))
    
    ==
    
    (.. '(1 2) getClass getProtectionDomain getCodeSource getLocation)
    

    Java Collection

    Clojure提供的Collection支持并发和事物内存机制,性能各方面也优于Java本身的Collection类,所以我们推荐使用Clojure的Collection。然而有一点就是Java的array无法用Clojure的collection来模拟,因此其提供了make-array来创建Java的array。

    (make-array class length)
    (make-array class dim & more-dims)
    

    上面两种语句都会返回一个java array对象,我们可以使用Clojure提供的seq方法来包裹java array,生成一个clojure的sequence对象。

    可以使用下面的方法来获取clojure提供的array方法:

    (find-doc "-array")
    

    clojure也提供了一系列的低级操作来支持java array:

    (aset java-array index value)
    (aset java-array index-dim1 index-dim2 ... value)
    (aget java-array index)
    (aget java-array index-dim1 index-dim2 ...)
    (alength java-array)
    

    通常可以使用clojure的to-array方法直接将一个collection转换为java array:

    (to-array ["Easier" "array" "creation"])
    #<Object[] [Ljava.lang.Object;@1639f9e3>
    

    into-array提供to-array类似的功能,但是却可以制定array中每一个元素的类型,而不是Object

    (into-array String ["Easier", "array", "creation"])
    

    如果没有类名,into-array也会根据参数才猜测之。

    Cloure提供了amap函数来循环处理java array中的每一个元素

    (amap a idx ret expr)
    

    其表示,首先对传进的array - a 进行复制,并且把复制品绑定为ret,之后将对 a中的每一个元素执行expr,idx绑定的为当前元素的index。最后返回结果array。比如测试例子:

    (def strings (into-array ["some" "strings" "here"]))
    #'user/strings
    
    (seq (amap strings idx _ (.toUpperCase (aget strings idx))))
    ("SOME" "STRINGS" "HERE")
    

    areduce是非常类似于amap的高阶函数,它的功能稍微复杂点:

    (areduce a idx ret init expr)
    

    Convenience Functions

    Clojure作为一个函数式语言,是以函数为参数和返回值的,而Java并不具备该功能。因此Clojure提供了memfn宏用来将Java中的方法转化为Clojure中的方法,以便于作为参数或者返回值继续传递下去。

    (map .toUpperCase ["a" "short" "message"])
    java.lang.Exception:\ Unable to resolve symbol: .toUpperCase in this context
    
    (map (memfn toUpperCase) ["a" "short" "message"])
    ("A" "SHORT" "MESSAGE")
    

    更好的办法是利用匿名函数来包裹java函数:

    (map #(.toUpperCase %) ["a" "short" "message"])
    ("A" "SHORT" "MESSAGE")
    

    Clojure还提供了一个检查给定对象是否属于某种类的判断语句instance?

    (instance? String 10)
    false
    

    Clojure为字符串提供了format函数来代替java本身的format函数

    (format "%s ran %d miles today" "Stu" 8)
    "Stu ran 8 miles today"
    

  • 相关阅读:
    rpcbind禁用不了,111端口无法释放?
    python3 pexpect 自动交互修改linux系统密码
    pip将包安装到指定位置
    使用openssl对文件进行加密解密
    james-2.3.2.1发邮件慢,不能多线程同时发
    java指令执行一个class文件并指定依赖包的路径
    ltib for imx280 tips
    使用net-snmp的snmptranslate命令验证MIB文件
    嵌入式linux去掉开机进度条,更换背景,换企鹅logo
    使用cppcheck对C代码进行静态检查
  • 原文地址:https://www.cnblogs.com/mmjx/p/2217084.html
Copyright © 2011-2022 走看看