问问如何组织julia的函数

julia新手,一直用matlab。谁能讲讲julia的文件和函数的关系是什么?matlab很简单,一个文件就是一个函数,想用什么函数,就把文件所在的路径填到path里就行了。julia到底是啥关系?想采用matlab的方式管理函数,该怎么弄?难道我要挨个函数“include”?太麻烦了吧?还有模块的功能,最近看魏坤的书,看了半天也不清楚文件、函数、模块到底都怎么组织到一起的?都怎么用?越来越糊涂

1 个赞

*.jl 文件与函数

一个文件里可以放许多函数,你也可以放到多个文件里。
像 matlab 那样一个文件放一个也行,但文件名和函数名并没有对应关系

你在一个文件里写了许多函数后,include 一次就都可以用了。
你想学 matlab 当然得 include 许多次,你或许能写个宏自动导入。

讲道理大多数编程语言都是这样做的,有少数能自动寻找依赖的除去,像 C/C++ 也是靠头文件批量导入函数。一个文件一个函数还是少数语言的选择,大多数语言都是一个文件内写很多函数,通过头文件、模块的形式指定导出的函数,然后导入一次就都能用了。

综上不建议这样做。我都觉得这不是一个好的编程风格。


模块

模块一般开发包才会用到。
模块是一个代码块 module MyModule 多行代码 end,一般就一个文件里放一个,你放多个也可以。
里面的函数默认不导出,你可以通过 export 导出你想要导出的变量或者函数。

导入模块内的函数用:usingimport ,具体的区别看文档,体会一下那个表格,或者自己多试试就知道了:

我对模块的看法是,搞包开发才把整个包封城一个模块,然后对外提供一些函数,作为 API。
一般都用不上。多个模块互相 include 或者 using 就容易翻车,这就不多展开。

模块的另一个功能就是隐藏内部细节,这也算是 API 的意义之一。API 是承诺要稳定的,而内部实现随时可以改动,只要不影响 API。

模块例子:Base 模块

Base 模块默认会加载,一些常用的函数会放在这里。
源代码见:

这整个文件夹以及子文件夹的内容都是。

我们打开 Base 模块定义文件看看。

模块与文件名同名只是习惯,不同名也没有影响。include 时用文件名,using 时用模块名。

大致结构如下

baremodule Base # baremodule 是特殊的模块,它不会加载 Base 模块

# 一些 using
using Core.Intrinsics, Core.IR
...

# 一些 include
## Load essential files and libraries
include("essentials.jl")
include("ctypes.jl")
...
include("exports.jl") # 导出都放在这个文件里

end # baremodule Base

可以看出 Base.jl 主要起一个索引的作用,它包含其他文件,函数的具体实现在其他文件内面。
全部加载到 Base.jl 里然后通过 exports.jl 里指定需要导出的函数。

这里只是要导出的函数太多了,所以单开一个文件。里面其实只有一句话 export 函数名,...
只不过太长了一个函数名换一行。一般导出的函数较少时就都写在一个里面了。

单文件例子:bool.jl

一般自己写点函数就长这样:

bool.jl 见名知意,放着和布尔类型 Bool 有关的函数,很短不到 120 行。它包含在 Base 模块里。
不过可以单独拿出来用,所以这里假装只有这一个文件。

文件的结构没啥好说的,非常简单:这个文件都没导入其他包,一个文件里全部都是函数定义,带有很多文档注释。

写 julia 代码像这样做就行了,想做点什么就放到一个函数里。功能差不多的函数就放到一个文件里。
等到有需求给别人用了,想要指定能用的函数就再封装到模块里。

大多数时候都是一个或几个文件搞定所有事情。即使在程序入口,也就是程序开始运行的那个文件里, julia 也提倡把东西都封装到函数里。你可以搞一个 main 函数,或者其他的名字,把初始化、调用其他函数的代码封装到这个函数里,然后最这个文件的最下面调用它 main()
除此之外文件里只有函数导入、函数定义。

最好不要像其他脚本语言那样在顶层作用域,也就是文件中直接写一堆调用的代码。这时候这些代码的变量都是全局变量,然后就会很慢。


matlab 也可以把很多函数写在一个文件里的。

我看有人就是开头一个 main 后面再写一堆要用的函数。这样就不用分多个文件了。

2 个赞

多谢多谢,您这个回答很到位了,能有这么详细的回答,很感动。
我只对fortran和matlab熟悉些。C++不熟。不过实在忍受不了一个文件里有很多函数,以前看fortran程序一个文件一大堆subroutine,头都大了。虽然大家都觉得matlab不是好的编程风格,但是我喜欢matlab的一个原因就是程序清爽,至少比fortran看着舒服。我没编过大项目,也理解不了matlab编程风格有何不妥。

程序文件的组织应该是个大学问,很奇怪很多编程教程里都不太提这个事情,不明白。

因为速度原因,我现在想把一个matlab的程序包改成julia版本的。

按照您的意思,我想是不是可以写个模块把改写的函数include进来,然后export就行了。

还有我不太明白julia的自己写的“库”(我不知道改如何表达)的path怎样才能让系统知道,刚查了一下,好像是
path =“E://xxxx//CalFemJl//fem”
push!(LOAD_PATH,path)
但是试了发现不太好使。
matlab有gui是很简单的。直接填上保存就好了。

另外,julia有没有类似matlab的clear all之类的命令。从matlab转过来,不容易,请谅解。

封装成模块先不着急,这个是锦上添花的事,同类型的事还有写文档。等功能都能用了再搞。

我的建议是就按功能划分把函数都尽量放到同一个文件里。

include 的时候可以用完整路径,或者相对当前文件的路径,一般都是在同一个目录下,或者同目录的某个子文件夹下,所以直接写文件名 include("file2.jl")include("lib/file2.jl") 就可以了。

LOAD_PATH 是用来加载模块的,等到折腾模块的时候再去研究。
其实你封装成模块,一个文件一个函数一个模块,依旧是要写一堆 using,跟 include 没有本质的区别。

清爽就意味着一大堆 include,你可以把这些 include 语句单独放到一个文件里,然后 include 这个文件,但总归是要写的。

比较长大概多于 1 屏幕的函数放在一个文件里可以接受。太短的还是都放一起吧。


其实是有的。“设计模式” 就是研究这个事的,一般都比较宏观,可能在模块、API 这个层面上。

这4本开源书的后2本介绍了一些开源软件的架构,不过讲的比较宏观。

木有

3 个赞

如果写成main()函数,的确就不用clear all了

多谢!信息点比较多,我再慢慢消化一下

补充一点。

julia 的函数组织是按照类型来的。julia 里一般不搞 OOP 面向对象编程。
一般是对某个类型写一堆函数放到一起。

举例就是上面的 Bool 他相关的逻辑运算、算数运算,和其他类型的转换等等函数都放到一起。

julia 的函数都不长,并且 julia 推荐把纯函数拆分出来,比如你有一个计算公式,还需要给某些值初始化,那么就可以拆成两个函数,一个就是数学等价的公式,输入什么输出什么。
另一个函数调用这个公式,并且初始化或者处理参数。

函数参数太多,可以打包成元组、封装到结构体里面传进去。这些纯函数 julia 会有相应的优化。
特别短的函数比如求二维两点间欧氏距离,也可以写成一个函数。julia 会自动内联的,不用担心函数调用开销。

当然你就用一次欧氏距离也没必要弄一个函数了。
不过右对应重要公式的还是建议写成函数,
并加上详细的注释。

中文社区有个简单的例子可以看看,点那个 2763v3.0.jl 可以展开以查看代码


看你提到了 FEM 做有限元?

可以看看

谢谢。其实对我来说现在最重要的是怎样让程序转起来。看样子按照我原来的用matlab习惯有点困难。的确做有限元,当然都是很简单的东西。

想请教您一下,自己封装好的模块(API),如何让别人也可以调用呢?