Julia Language

作为一种专为科学计算设计的工具,Julia 的目标是构建一个前所未有的集易用、强大、高效于一体的语言,除此之外,Julia 还希望具有以下优势:
- 采用 MIT 许可证:免费又开源
- 用户自定义类型的速度与兼容性和内建类型一样好
- 无需特意编写向量化的代码:非向量化的代码就很快
- 为并行计算和分布式计算设计
- 轻量级的“绿色”线程:协程
- 低调又牛逼的类型系统
- 优雅、可扩展的类型转换和类型提升
- 对 Unicode 的有效支持,包括但不限于 UTF-8
- 直接调用 C 函数,无需封装或调用特别的 API
- 像 Shell 一样强大的管理其他进程的能力
- 像 Lisp 一样的宏和其他元编程工具
这篇文章主要介绍如何使用 Julia 语言创建项目、管理依赖包等内容,以及一些特殊的的语法和特性。Julia 版本为 v1.11,使用的 IDE 为 VS Code。
项目的创建
Julia 项目的环境配置一般由项目文件Project.toml
和清单文件Manifest.toml
体现。在正式开发 Julia 项目的时候往往还需要专属的环境配置文件。这样才能与全局环境区别开。这么做有 3 个好处:
- 一旦有了专属的环境配置文件,我们的项目就可以独立地管理依赖包了。
- 针对某个 Julia 项目的程序包管理操作不会影响到全局的环境配置。反之亦然。
- 拥有环境配置文件的 Julia 项目可以为项目的分发(以供他人使用)做好准备。
如此一来,上述构建的 Julia 项目可以成为独立的、可重用的以及对分发友好的项目。
现在开始演示如何创建一个新的 Julia 项目。一般地,创建一个 Julia 项目分为以下几步:
Step 1. 首先在命令行中通过输入julia
命令进入到 REPL 环境,接着键入shell
进入 shell 模式中,并使用cd
命令进入某个专用的目录(比如~/Projects
)。此时可以使用pwd
函数确认一下当前的目录:
1 | julia> pwd() |
Julia中的pwd
函数的含义就是打印当前的工作目录,与在命令行中输入pwd
命令的作用是类似的,只不过调用表达式pwd()
的求值结果是一个字符串。
Step 2. 在确认了工作目录之后,按]
键切换到 REPL 环境的 pkg 模式,然后输入generate
命令,并后跟一个空格和项目的名称NewProj
:
1 | (.11) pkg> generate NewProj |
注意,generate
命令后面追加的参数是我们要创建的 Julia 项目的名称,这个命令在当前路径下创建了一个名为NewPorj
的目录,并在该目录下生成了两个文件。一个是项目文件Project.toml
,另一个是src
目录(即源码目录)下的源码文件NewPorj.jl
。
我们先来看项目文件,它的内容如下:
1 | name = "NewProj" |
这里有 4 个条目,分别代表项目的名称、UUID、作者信息和初始版本号。其中的 UUID 是 Julia 的程序包管理器自动生成的。而项目作者信息是从当前操作系统中的 Git 配置信息复制过来的。
我们再来看源码文件NewProj.jl
的内容:
1 | module NewProj |
其中只定义了一个名为NewProj
的模块。并且,该模块仅包含了一个可以向计算机的标准输出打印Hello World!
的函数greet
。这显然只是一个简单的程序模板。不过,它为我们后续的编码开了个头。
注意,这个源码文件是有重要意义的:
- 该文件可以被称为
NewProj
项目的源码入口。或者说,它是这个项目的主源码文件。这是由于该文件的主文件名与项目的(主)名称是一致的。 - 该文件中定义的(最外层的)模块
NewProj
将会是其所属项目的主模块(或者说默认模块)。这是由于该模块的名称与项目的(主)名称是一致的。
正因为有了这样的一个源码文件,使得NewProj
项目可以被 Julia 视为一个程序包。更明确地讲,如果存在一个名为X
或X.jl
的 Julia 项目,只要该项目包含一个相对路径为src/X.jl
的源码文件,并且在该文件中定义的最外层模块名为X
,那么它就是一个有效的程序包。
引入程序包
既然NewProj.jl
项目已经是一个有效的程序包了,那么我们就可以在代码中对它进行引入(更明确地说,是引入它的主模块NewProj
)。具体怎么做呢?
当我们试图在全局环境中导入该程序包的时候,Julia 会提示找不到这个程序包:
1 | julia> import NewProj |
为了解决这个问题,需要首先在 REPL 环境下使用;
命令进入 shell 模式,接着使用cd NewProj
命令进入到NewProj.jl
项目所在的目录,然后切换到 pkg 模式,并输入命令activate .
。注意,这里的输入是activate
加一个空格
,再加一个英文点号.
。示例如下:
1 | julia> pwd() |
命令activate .
的作用是把程序包管理器的操作目录切换到当前项目所在的目录,即:./NewProj
,而原本默认的操作目录是\.julia\environments\v1.11
,对应于 Julia 的v1.11
版本的全局环境。如果希望切换回全局环境,那么只需要再次输入命令activate
(不加任何参数)即可。
在这之后,我们再在当前的 REPL 环境中导入NewProj
就不会有问题了:
1 | julia> import NewProj |
如果确实需要在全局环境中引入NewProj
,那么可以先把这个项目上传到一个代码托管仓库(比如 GitHub)中,然后再使用 Julia 的程序包管理器把它安装到本地的仓库目录。
比如,如果NewProj.jl
项目以及被托管到了 GitHub 上了,经查询可知它的 git 地址是git@github.com:gypsophila-cx/NewProj.git
,那么现在就可以直接在 REPL 环境中进行如下操作将它纳入到全局环境中:
1 | (v1.11) pkg> add git .com:gypsophila-cx/NewProj.git |
一旦NewProj
程序包被记录在了全局环境的项目文件中,在全局环境下引入它也就不会有问题了。
代码编写
函数
通常情况下,我们在 Julia 中定义函数的方式是这样的:
1 | function IterativeSovler(A::AbstractMatrix{T}, b::Vector{T}, tol::T=1e-6, max_iter::Int=1000) where T |
上述代码给出了一个编写迭代求解器的示例。在 Julia 中,函数的参数类型是可以显式声明的,也可以不声明,这取决于程序的需求。类型声明能够帮助编译器做出优化,并为用户提供更清晰的接口。虽然类型声明不是强制性的,但在某些场合,显式声明参数类型能够提高性能、避免错误,并提升代码的可读性,而在编写时不指定类型会增加运行时开销,因为 Julia 需要动态决定如何处理参数类型。
另外,上述代码中where T
语句用于定义类型参数(type parameters),它表示函数、类型或结构体中使用的类型变量,这里where T
使得函数IterativeSovler
的类型能够适配不同的数据类型。这样做的好处有:
- 泛化:
where T
使得IterativeSovler
函数可以处理不同类型的数据。例如,如果传入一个Float64
矩阵A
和向量b
,那么T
就会被推断为Float64
;如果传入Complex{Float64}
类型的矩阵和向量,T
就会被推断为Complex{Float64}
。这使得函数变得更加灵活,能够处理各种数据类型。 - 类型安全:使用类型参数
T
允许在编译时进行类型检查,从而避免类型错误。编译器会确保在调用函数时传入的所有参数(矩阵A
和向量b
)都具有一致的类型。
相关资料
- 英文官方文档:Julia Documentation
- 中文官方文档:Julia 中文文档
- Title: Julia Language
- Author: Gypsophila
- Created at : 2025-01-20 13:59:13
- Updated at : 2025-01-25 23:58:43
- Link: https://chenx.space/2025/01/20/Julia/
- License: This work is licensed under CC BY-NC-SA 4.0.