- Clojure 教程
- Clojure - 首页
- Clojure - 概述
- Clojure - 环境
- Clojure - 基本语法
- Clojure - REPL
- Clojure - 数据类型
- Clojure - 变量
- Clojure - 运算符
- Clojure - 循环
- Clojure - 决策
- Clojure - 函数
- Clojure - 数字
- Clojure - 递归
- Clojure - 文件 I/O
- Clojure - 字符串
- Clojure - 列表
- Clojure - 集合
- Clojure - 向量
- Clojure - 映射
- Clojure - 命名空间
- Clojure - 异常处理
- Clojure - 序列
- Clojure - 正则表达式
- Clojure - 断言
- Clojure - 解构
- Clojure - 日期和时间
- Clojure - 原子
- Clojure - 元数据
- Clojure - StructMaps
- Clojure - 代理
- Clojure - 观察者
- Clojure - 宏
- Clojure - 引用值
- Clojure - 数据库
- Clojure - Java 接口
- Clojure - 并发编程
- Clojure - 应用
- Clojure - 自动化测试
- Clojure - 库
- Clojure 有用资源
- Clojure - 快速指南
- Clojure - 有用资源
- Clojure - 讨论
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 中的 Require 语句
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-1.6.0.jar 之类的文件,这些文件是运行任何基于 Clojure 的应用程序所必需的。
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"]])