贡献者: 待更新
本文授权转载自郝林的 《Julia 编程基础》。原文链接:第 1 章:起步。
我们应该对上述程序的功能稍作改进。因为它现在只能向 Julia 打招呼,不论执行它的人是谁。我们需要让它根据执行人给定的参数值来自定义它打招呼的对象。顺便说一句,我会把这一程序的改进版本放在 src/ch01/args
路径下。
首先,我们要改变一下调用 println
函数时传给它的那个参数。修改后的调用表达式如下:
println("Hey, $(name)!")
我只改动了几个字符,即:把 Julia
改成了 $(name)
。后者代表了一个插值(interpolation)。对于插值来说,前缀 $
(和后缀)之间的内容可以是一个变量的名称,也可以是一个表达式。在这里,我放入的是变量 name
的名字。在 println
函数向目的地输送内容之前,它会把 name
替换成该变量在那一刻时的值。
当然,变量 name
现在还不存在。我们还需要在这行代码的前面添加一些东西。
name, _ = MyArgs.get_parameter("name", true)
if name == ""
name = "handsome"
end
上面这 4 行代码的主要功能是定义 name 变量,并为它赋予合适的值。第一行中的 MyArgs
代表了一个模块。而表达式 MyArgs.get_parameter("name", true)
则代表了对这个模块下的函数 get_parameter
的一次调用。在调用时,我们传给了它两个参数值,即:String
类型(也称字符串类型)的值 "name"
和 Bool
类型(或者说布尔类型)的值 true
。
这里的模块代表的是一块程序。原则上讲,这块程序可以包含任意行的代码。我一会儿再说怎么定义一个模块。现在你只需要知道,在我们调用 MyArgs.get_parameter
函数后,它会返回两个结果值。在同一行中,我把这两个结果值分别赋给了变量 name
和 _
。
符号 =
代表了 “赋值”
这个动作。这意味着,它右边的表达式所产生的结果值会被赋给左边的变量。注意,右边的结果值的数量和左边的变量的数量必须相同。在这里,它们的数量都是两个。
你可能会问:_
是什么?它实际上是一个占位符。你可以把它想象成一个垃圾桶。当我们不再需要某个值的时候,就可以把它扔进(赋给)这个垃圾桶。这么做一般有两个原因。其一,让 Julia 的垃圾收集器及时地回收这个不再被使用的值所占用的内存空间。其二,保持程序的完整性和可读性。换句话说,即使一个值或者一个变量不再有用了,我们也要进行妥善的处理。
所谓的垃圾收集器是指,用于自动地收集和清扫内存垃圾的内置程序。大多数现代编程语言都会提供垃圾收集器。简单来说,当用户程序中的一些代码以及它们产生的数据不再有用的时候,垃圾收集器就会识别它们,并把它们所占用的内存空间收回,以便重复利用或者还给操作系统。
再说回我们的程序。我们在第一行代码中调用了 MyArgs.get_parameter
函数,并用它返回的第一个结果值为 name 变量赋了值。紧随其后的,是一个由 if
语句构成的代码块。
if name == ""
name = "handsome"
end
if
语句用于有条件地执行代码。它以关键字 if
作为起始,并以关键字 end
作为末尾。在 if
右边的就是一个条件,即:name == ""
。这是一个判等表达式。它判断的是变量 name
的值是否与空字符串 ""
相等。
在我们的设计中,如果我们在执行这个程序的时候没有通过参数指定一个问候对象的名字,那么这里的 name
变量的值就会是 ""
。因此,这个 if 语句代表的逻辑就是,如果我们没有指定问候对象的名字,那么就把 name
变量的值设置成 "handsome"
。
记住,在 if
关键字和条件代码的下一行就是满足条件时需要执行的代码。当然,这样的代码可以有多行。但不管怎样,这些代码都需要被缩进。也就是说,它们要比包含了 if
关键字的那一行代码更靠右一些。一般情况下,我们需要在这些代码的左边插入固定数量(比如 4 个)的空格或者一个制表位。
还要注意,关键字 end
与关键字 if
是左对齐的。并且 end
是需要独占一行的。这个关键字在 Julia 程序中是非常常用的。它通常作为一个代码块的结束标识。比如,我们在写模块、函数、if
语句、for
语句、try...catch
语句等等代码块时都会用到它。
再来说 MyArgs
模块。我在改进版本的 main.jl
的开始处定义了这个模块。代码如下:
module MyArgs
include("args.jl")
end
它由关键字 module
、模块名称 MyArgs
、关键字 end
,以及被夹在中间的代码组成。注意,在模块的定义中,首尾两行之间的那些代码可以不缩进。这主要是考虑到整个文件的内容只包含一个(或寥寥几个)模块定义的情况。在这种情况下,如果中间的代码都缩进,那么就等于几乎所有的代码都要缩进了。这个工作量往往是没必要的,而且这样的代码也是不美观的。
在我们的 MyArgs
模块的中间只有一行代码。它也是一个表达式,代表了对 include
函数的调用。这个 include
函数接受一个字符串类型的参数,而且这个参数的值需要代表一个 Julia 源码文件的路径名。简单来说,它会把参数值指定的源码文件的内容复制、黏贴到调用它的代码那里。也可以说,它会用我们指定的源码替换掉调用它的那行代码。
我们在这里传给 include
函数的参数值是 "args.jl"
。这个源码文件与改进版本的 main.jl
处在同一个目录下,即:*src/ch01/args*
。我在该文件中定义了一个名叫 get_parameter
的函数。这个函数的定义细节我就不讲了,你可以自己去看。其中只包含了寥寥几行代码,用于变量定义、函数调用、条件求值等。
那里有一些语法我们还没有讲,所以你看不懂也没关系。但是,我希望你在看过之后记录下自己有疑问的地方,并且带着这些疑问阅读本教程的后续部分。
现在让我们执行一下改进版本的 main.jl
文件吧:
$ julia --startup-file=no main.jl --name=Robert
Hey, Robert!
我在这次执行 julia
命令的时候给了它三个参数。这些参数之间是由空格分隔开的。第一个参数是我们已经熟知的 --startup-file
。而第二个参数是我要执行的源码文件。在它之后就是我为源码文件提供的参数了。
在第三个参数中,我以 --
为前缀。这主要是为了遵从 julia
命令的参数形式。紧跟在 --
之后的就是参数名 name
、等于号 =
和参数值 Robert
。因此,程序回显的内容就是 Hey, Robert!
。这是正确的。你可以改变一下第三个参数的值,然后看看效果。