Clojure 基本语法
为了理解 Clojure 的基本语法,让我们先来看一个简单的 Hello World 程序。
Hello World作为一个完整的程序
在一个完整的 Clojure 程序中编写“Hello world”。 下面是一个例子。
例
(ns clojure.examples.hello (:gen-class)) (defn hello-world [] (println "Hello World")) (hello-world)
上述例子需要注意以下事项:
程序将被写入一个名为 main.clj 的文件中。 扩展名 'clj' 是 clojure 代码文件的扩展名。 在上面的示例中,文件的名称称为 main.clj。
'defn' 关键字用于定义一个函数。 我们将在另一章详细介绍功能。 但是现在,知道我们正在创建一个名为 helloworld 的函数,它将拥有我们的主要 Clojure 代码。
在我们的 Clojure 代码中,我们使用'println'语句将“Hello World”打印到控制台输出。
然后我们调用 hello-world 函数,它又运行 'println' 语句。
上述程序产生以下输出:
Hello World
声明的一般形式
任何语句的一般形式需要在大括号中求值,如下面的示例所示:
(+ 1 2)
在上面的示例中,整个表达式用大括号括起来。 上面语句的输出是3. +运算符就像Clojure中的一个函数,用于添加数字。 1和2的值称为函数的参数。
让我们考虑另一个例子。 在本例中,'str'是用于连接两个字符串的运算符。 字符串“Hello”和“World”用作参数。
(str "Hello" "World")
例
如果我们结合上面的两个语句并编写一个程序,它将如下所示。
(ns clojure.examples.hello (:gen-class)) (defn Example [] (println (str "Hello" "World")) (println (+ 1 2))) (Example)
上述程序产生以下输出:
Hello World 3
命名空间
命名空间用于定义在 Clojure 中定义的模块之间的逻辑边界。
当前命名空间
这定义了当前 Clojure 代码所在的当前命名空间。
语法
*ns*
例
在 REPL 命令窗口中运行以下命令。
*ns*
输出
当我们运行上面的命令时,输出将取决于当前的命名空间是什么。 以下是输出的示例。 Clojure 代码的命名空间是
clojure.examples.hello (ns clojure.examples.hello (:gen-class)) (defn Example [] (println (str "Hello World")) (println (+ 1 2))) (Example)
加载 Clojure 包
Clojure 代码封装在库中。 每个 Clojure 库都属于一个命名空间,类似于 Java 包。 您可以使用 'Require' 语句加载 Clojure 库。
语法
(require quoted-namespace-symbol)
例
以下是此语句的用法示例。
(ns clojure.examples.hello (:gen-class)) (require ‘clojure.java.io’) (defn Example [] (.exists (file "Example.txt"))) (Example)
在上面的代码中,我们使用 'require' 关键字来导入命名空间 clojure.java.io,它具有输入/输出功能所需的所有功能。 因为我们没有所需的库,所以我们可以在上面的代码中使用 'file' 函数。
Clojure中的注释
注释用于记录您的代码。 单行注释通过使用;; 在该行的任何位置。 下面是一个例子。
例
(ns clojure.examples.hello (:gen-class)) ;; This program displays Hello World (defn Example [] (println "Hello World")) (Example)
分隔符
在 Clojure 中,可以使用弯曲或方括号括号来分割或分隔语句。
例
下面是两个例子。
(ns clojure.examples.hello (:gen-class)) ;; This program displays Hello World (defn Example [] (println (+ 1 2 3))) (Example)
输出
上述程序产生以下输出:
6
例
以下是另一个例子。
(ns clojure.examples.hello (:gen-class)) ;; This program displays Hello World (defn Example [] (println [+ 1 2 3])) (Example)
输出
上述程序产生以下输出:
[#object[clojure.core$_PLUS_ 0x10f163b "clojure.core$_PLUS_@10f163b"] 1 2 3]
空格
空格可以在 Clojure 中用于拆分语句的不同组件,这样可以让代码更加的清晰。也可以和逗号 (,) 运算符一起使用。
例如,以下两个语句是等效的,并且两个语句的输出将是 15。
(+ 1 2 3 4 5) (+ 1, 2, 3, 4, 5)
尽管 Clojure 忽略逗号,但逗号的使用让程序更便于阅读。
例如,如果你有一个哈希映射,如下(def a-map {:a 1:b 2:c 3})并要求在 REPL 窗口中的值,Clojure 将打印输出为{:a 1, :b 2,:c 3}。
结果更容易阅读,特别是如果你查看大量的数据。
符号
在 Clojure 中,符号等同于其他编程语言中的标识符。 但与其他编程语言不同,编译器将符号视为实际的字符串值。 由于符号是一个值,符号可以存储在集合中,作为参数传递给函数等,就像任何其他对象一样。
符号只能包含字母数字字符和“* +! /。 : - _?',但不能以数字或冒号开头。
以下是符号的有效示例:
tutorial-point! TUTORIAL +tutorial+
Clojure的项目结构
最后,让我们谈谈一个 Clojure 项目的典型项目结构。 由于 Clojure 代码在 Java 虚拟机上运行,因此 Clojure 中的大部分项目结构与在 java 项目中发现的类似。 以下是 Eclipse 中针对 Clojure 项目的示例项目结构的快照。
关于项目结构,有一下几个关键的地方需要注意:
demo_1 - 这是 Clojure 代码文件放在其中的包。
core.clj - 这是主要的 Clojure 代码文件,它将包含Clojure应用程序的代码。
Leiningen 文件夹包含像运行任何基于 Clojure 的应用程序所需的 clojure-1.6.0.jar 文件。
pom.properties 文件将包含诸如 groupId,artifactId和 Clojure 项目版本等信息。
project.clj 文件包含关于 Clojure 应用程序本身的信息。 以下是项目文件内容的示例。
(defproject demo-1 "0.1.0-SNAPSHOT" :description "FIXME: write description" :url "http://example.com/FIXME" :license { :name "Eclipse Public License" :url "http://www.eclipse.org/legal/epl-v10.html" } :dependencies [[org.clojure/clojure "1.6.0"]])