1.3 编写第一个程序

由于 Julia 程序可以作为脚本程序来编辑和使用(就像 Shell 和 Python 那样),所以 Julia 源码文件的内容可以非常简单。你可以把脚本程序看做是以普通文本的形式保存的、实现了一定的处理逻辑的计算机指令片段。脚本程序一般存储在一个单独的文件中,并可以由特定的工具读取和执行。比如,用 Bash(Bourne Again SHell)语言编写的脚本程序可以由bash工具来执行。又比如,用 Python 语言编写的脚本程序可以用python这个工具来执行。

与真正的程序相比,脚本程序的最大特点就是简单。它既没有高级的数据类型,也没有复杂的组织结构和流程控制,更不支持能够实现程序自我进化的元编程。而这些在 Julia 中都是存在的。因此,我们可以把 Julia 程序写得很简单,也可以把它写得很复杂。这取决于程序要实现的功能和需求,以及编写代码的人的设计风格和思考能力。

当然了,我们在初学一门编程语言的时候肯定是要从最简单的程序编写开始的。然后由浅入深,逐步地掌握它的编写方法、技巧和原理。本教程会专注于 Julia 程序的基本编写方法和技巧,并在有必要时涉及一些高级技巧和底层原理。

好了,我们现在就来编写我们的第一个 Julia 程序。我先呈现出代码再来解释。

文件 src/ch01/hello/main.jl

  1. # 示例的主文件。
  2. # - Julia version: 1.3.1
  3. # - Author: HaoLin
  4. # - Date: 2020-04-01
  5. println("Hey, Julia!")

上述代码被保存在了一个单独的文件中。我们先来看这个文件的名字。main.jl显然由两个部分组成。这两个部分由英文句号(或称点号).分割。我们一般把第一部分称为主文件名,并把第二部分称为扩展文件名。我们一般只会将代表了程序入口(或者说可以由julia命令直接执行)的那个源码文件命名为main.jl

扩展名jl用于表示这个文件是一个 Julia 程序的源码文件。你可能已经看出来了,jl就是 Julia 的缩写。实际上,所有的 Julia 源码文件的扩展名都必须是jl

这个源码文件的内容也包含了两个部分。第一部分为程序注释,第二部分为程序代码。

在 Julia 中,程序的注释可以是单行的,也可以是多行的。如果是单行的注释,我们需要以#作为这一行的开始。比如:# 这是一个单行的注释。如果是多行的注释,我们就需要显式地标示注释的开头和结尾。更具体地说,开头的标示是#=,结尾的标示是=#。并且,这两个标示通常都应该独占一行。上述源码文件中的第一部分就是这样的。

在这块注释中,我写明了这个源码文件在编写时的 Julia 版本号、作者(也就是我)的代号,以及该文件被创建时的日期。这是一种比较标准的简单写法。当然,每一个工程化的软件开发团队都会有自己的代码编写规范,其中会包含对注释风格的规定。因此,我在这里展示的只是其中的一种写法而已。不过,我建议你在编写 Julia 源码文件时一定要添加包含这几条重要信息的头部注释。

另外,我们也可以用 Markdown 格式的文本作为注释。这是 Julia 所独有的注释方式。其做法简单来说是,在一段代码(比如完整的程序定义)的开始行的上一行,写入 Markdown 格式的注释,并用三联的双引号将其包裹起来。注意,前后的三联双引号都需要独占一行。一个简单的示例如下:

  1. """
  2. get_parameter(key::String, first::Bool=true)
  3. 根据参数获取指定的命令行参数值。
  4. 参数`key`代表命令行参数的名称。参数`first`代表一种获取策略。
  5. 如果参数`first`的值为`true`,那么无论有多少个同名的命令行参数,都只获取第一个。否则只获取最后一个。
  6. """
  7. function get_parameter(key::String, first::Bool=true)

Julia 自有一套 Markdown 注释规范。可参见 Julia 官方文档及其源码。

我们再来说文件中的第二部分。它只包含了一行代码。我在本章的第一节中展示过与之类似的代码。

这行代码实际上是一个函数调用表达式。其中的println是函数的名称。这个函数的功能是,向指定的输出(设备)上输送指定的内容。它常常被简称为打印函数。紧跟在它后面的、由一对圆括号包裹的内容代表了一个动作。这个动作就是“调用”。圆括号中的内容就是我们在调用这个函数时传给它的参数值。在这里,这个参数值是字符串"Hey, Julia!"

你可能没有发现,我在这里并没有为它指定输出(也就是输送的目的地)。这时,指定的内容会被输送到标准输出(standard output)上。如果想指定输出的话,那么代表输出的那个参数值就应该被放到圆括号中的最左边,然后用英文逗号,与原先的参数值"Hey, Julia!"分隔开。如此就形成了一个参数值的序列,或者称之为参数值列表。例如,println(io, "Hey, Julia!")。其中的io是一个变量的名称,用于表示代表了输出的那个参数值。

好了,现在让我们使用julia命令来执行这个简单的程序。我们需要先进入这个源码文件所在的目录,然后这样做:

  1. $ julia main.jl
  2. Greetings! 你好! こんにちは? 안녕하세요?
  3. Hey, Julia!

第一行最左边的$代表命令行提示符。它表示我们是在命令行中执行julia命令的。我在后面的类似场景下都会带上这个提示符。这也可以帮助你区分我们输入的命令和命令回显(或者说返回和显示)的内容。

在这里,我们输入的命令是julia main.jl。显然,我把上述源码文件的路径名作为参数传给了julia命令。该命令在收到这个参数后会立即读取相应的源码文件,并执行其中的代码。

你可能会有疑问,第二行的内容好像与我们的程序并不相关啊。的确如此。实际上,julia命令在启动时会先去执行一个名叫startup.jl的源码文件。正是其中的代码向标准输出(在这里是当前的命令行界面)输送了第二行的内容。在默认情况下,startup.jl文件中的代码如下所示:

  1. println("Greetings! 你好! こんにちは? 안녕하세요?")

文件startup.jl也被称为 Julia 的启动文件。它被保存在当前计算机的文件系统中的 Julia 配置目录下。比如,在 macOS 操作系统中,它的存放路径就是~/.julia/config/startup.jl

如果你不想看到这行多余的内容,那么有两种方式可以达到目的。第一种方式,删掉startup.jl文件中的那行代码。第二种方式,在执行julia命令时追加参数--startup-file,并把参数值设置为no。比如这样做:

  1. $ julia --startup-file=no main.jl
  2. Hey, Julia!

这样一来,命令回显的就只剩下我们的程序所输送的内容了。

到这里,我们的第一个程序已经成功地执行了!我相信你已经对它有了足够的了解。但这只是一个开始。我们马上就要着手改进这个程序。