贡献者: addis
Julia 从 Matlab 和 C/C++ 借鉴了不少语法,如果你两种语言都已经会了,那么 Julia 是十分简单的。本章的目的就是为已经学习过类似语言的读者提供一个 Julia 语言的快速入门笔记。
Ubuntu/Debian 安装方法。
sudo apt install julia
# 或者
sudo snap install Julia --classic
如果版本较老,最好还是从官网下载安装包,直接解压即可使用 bin/julia 执行文件。也可以创建软链 sudo ln -s /home/用户名/julia-xxx/bin/julia /usr/bin/julia
Windows 默认安装目录:C:\Users\<Username>\AppData\Local\Programs\Julia-<version>
要检查该路径,可以用 print(Sys.which("julia")) 或者 print(Sys.BINDIR)(如果不用 print,Windows \ 会打印为 \\)。
另外本地的 Jupyter Notebook 也支持 Julia。在 julia 命令行里面运行 import Pkg,Pkg.add("IJulia")。现在打开 Jupyter notebook 就可以新建 julia 文档了。
至于 IDE,Juno 和 JuliaPro 都已经停止更新,当前(2023-3)最热门的 IDE 环境是 Julia 的 VScode 拓展,支持逐行调试。
println("hello world") 会自动换行。print 则没有自动换行。
#,或者 #=一些注释=#,多行注释也可以和 python 一样用 """..."""。
Ctrl + C 可以复制,未选中时用于中断执行。
Ctrl + V 用于粘贴。
Ctrl + D 退出或者 exit() 退出。
Ctrl + R 搜索命令历史。
ans 变量和 Matlab 一样,用于显示上一次运算的输出结果(结果赋值给变量的除外)
println("$var1 some words $var2") 中 var1, var2 可以是数字、字符串等,这和 println(var1, " some words ", var2) 等效。其实这是字符串的功能而不是 println 特有的。要避免混淆用 $(var),如 $(var)a。
io = IOBuffer(); println(io, "Hello Julia!"); s = String(take!(io)) 可以让 println 输出到字符串。
Main. 模块中,如 x = 3; println(Main.x)
b = 2a 和 c = 2(b+3) 都可以省略乘号。注意 1/2a 相当于 1/(2a)
2/3 返回双精度类型 Float64 而不是整数
2//3 返回 Rational{Int64} 类型,相当于用两个 Int64 整数来表示分数,分数之间的运算没有误差
1 + 2im,相当于 ComplexF64(0,2)。又例如 1//2 + (3//4)im 的类型是 Complex{Rational{Int64}}
pi 的类型是 Irrational{:π},@which pi 可以看到它的模块是 Base.MathConstants.pi。
ℯ 即 Base.MathConstants.e 或 Base.MathConstants.ℯ,类型是 Irrational{:ℯ}。
typeof() 查看某个变量的类型(python 是 type)
::类型 限制变量类型。例如 a::Int = 1.2; 会报错。
! 可用于变量名或函数名的非首字符。一般来说,在函数名最后加 ! 用于表示该函数的参数会被修改。
typemax(Int64),typemin(Int64)
BigInt 和 BigFloat(底层是 GMP)
nothing(类型为 Nothing <: Any),然后运行垃圾回收 GC.gc() 即可。
typeof(Float64) 是 DataType。
@isdefined 变量名 可以查看某变量是否有定义。
x = 100
function qux()
global x # 需要修改 x(只读无需声明)
x = 200
end
@which 名字 可以查看一个名字在哪里定义,如函数、宏(@which @宏名)、模块、全局变量、类型名等。
@edit 命令 可以用默认编辑器打开定义代码,例如 1+1,sin(1)。
julia 文件名.jl 运行脚本,用 julia 文件名.jl <arg1> <arg2> 给出 arguments
include("/Users/addis/Desktop/main.jl")(windows 路径不区分大小写),也支持反斜杠,但要转义成 \\。在任何地方用 include 相当于把文件代码直接插入到当前位置。
abspath(PROGRAM_FILE) == @__FILE__
~/.julia/config/startup.jl,julia 文件名.jl 会先运行启动脚本再运行 文件名.jl。要跳过启动脚本,用 julia --startup-file=no 文件名.jl(只能是 [yes|no])。如果存在环境变量 JULIA_DEPOT_PATH,默认启动脚本路径就是 JULIA_DEPOT_PATH/config/startup.jl(参考 julia --help)
julia 文件名.jl arg1 arg2 ...,后面的参数可以在脚本中通过全局变量 ARGS 访问。一个分析 ARGS 的库叫 ArgParse。
julia -e '若干julia语句' 可以执行若干语句而不打开 REPL。
tr(A),行列式 det(A),逆 inv(A),本征值 eigvals(A),本征矢 eigvecs(A),本征对 tmp = eigen(A)(tmp.vectors, tmp.values),LU 分解 factorize(A)
Symmetric,Hermitian,UpperTriangular,LowerTriangular,Tridiagonal,SymTridiagonal,Bidiagonal,Diagonal
using SparseArrays,然后 S = sparse(行标矢量,列标矢量,非零元矢量) 可以创建 CSC 格式的矩阵:SparseMatrixCSC{矩阵元类型, 指标类型}
using LinearAlgebra.BLAS;m=3;n=4;kl=1;ku=1;alpha=1.;beta=0.;A=rand(kl+ku+1,n);x=rand(Float64,n); y=zeros(Float64,m); gbmv!('N', m, kl, ku, alpha, A, x, beta, y) 其中矩阵尺寸为 m 乘 n,上下子对角线数量 ku, kl。
geev!(jobvl, jobvr, A);对称矩阵本征问题 syev!(jobz, uplo, A);对称三对角矩阵本征问题 stev!(job, dv, ev)
b = 3;
# 循环内的 `a` 的值不影响循环外的 `a` 的值
# 循环内初次定义的其他变量在循环外也无定义
for a = 1:5 # 也可以用 `in` 代替 `=`
if a < b
println(a, " < ", b)
elseif a > b
println(a, " > ", b)
else
println(a, " = ", b)
end
end
其中 1:5 的类型是 UnitRange{Int64}。若令 a = 1:5,可以使用 a[i] 获取 “元素”。类似地,1:2:5 的类型是 StepRange{Int64, Int64}。
for i in [1,4,0]
if 条件; 命令; end
for (i, e) in enumerate(my_container)
首先介绍 map() 函数
map(sin, [1,2,3]) # Returns [sin(1), sin(2), sin(3)]
map(+, [1, 2, 3], [10, 20, 30]) # Returns [11, 22, 33]
map(容器) do 元素: ... return 值; end 可以对每个元素做某种处理,并把结果生成 Vector
result = map(1:4) do n
product = 1
for i in 1:n
product += i
end
return product # 该 return 和函数中的一样可以省略
end
# 运行结果
# 4-element Vector{Int64}:
# 2
# 4
# 7
# 11
f(x) do a, b
body
end
# 相当于:
f(x, (a, b) -> begin
body
end)
# 即定义一个 lambda 函数并传入 f() 的最后一个参数
try
一些命令
catch y
if isa(y, 错误类型1)
一些命令
elseif isa(y, 错误类型2)
一些命令
end
end
DomainError(例如 sqrt(-1)),BoundsError(数组指标超出范围)。
函数定义
function sphere_vol(r)
return 4/3*pi*r^3
end
定义含名参数如
function greet(name; greeting="Hello")
println("greeting, $(name)!")
end
return 会自动返回最后一个语句的值(含 nothing)。此时 a = myfun() 会得到 nothing 不会报错。
return a, b, c 或 return (a, b, c) 实际上是返回一个 Tuple。此时 ret = myfun() 会得到该 Tuple,但 a, b, c = myfun() 会把 tuple 展开。允许 a, b = myfun()。
struct)
function greet(x)
println("x");
end
function greet(s::String)
println("s");
end
现在打 greet,会显示 greet (generic function with 2 methods)。greet(1) 会显示 x,greet("a") 会显示 s。
f1(args...) = f2(args...)
function outer()
z = 15 # z is local to outer()
function inner()
println(z) # inner() 可以访问 outer() 的变量
end
inner() # Output: 15
end
add(a, b) = a + b
等效于
function add(a, b)
return a + b
end
和 Python 类似
function code_lowered(x:Float64, y::String;
kw1::Bool=true, kw2::Symbol=:default)
# ...
end
time()
第三方画图包 Plots,无需安装
using Plots
x = 1:10; y = rand(10); # These are the plotting data
plot(x,y)
要把任意变量存到文件,用 using Serialization,除此之外常用的还有 using JLD2。
using Serialization
a = randn(100,100)
f = serialize("file1.dat", a)
a1 = deserialize("file1.dat")
println(a == a1)
pwd(),更改路径 cd()
readdir() 返回当前路径或指定路径中的文件和文件夹
f = open("文件名", "r") 打开文件读取,close(f) 关闭文件。
eof(f) 用于判断是否到达文件末尾
s = readline(f) 读取下一行
s = read(f, String) 整个文件读入字符串
using DelimitedFiles; m = readdlm("文件名") 从文本文件中读取矩阵
write(file, str) 把字符串写入文本文件
using DelimitedFiles; writedlm("文件名", 矩阵) 把矩阵写入文本文件(用空格与回车)
module 模块名; 定义变量、类型、函数; end。
import 模块名 后,调用函数(或变量)用 模块名.函数名,但 using 模块名 后,可以省略 模块名.
using 指定内容,用 using 模块名: 函数1, 函数2, 变量3。
import 模块名: 函数1, 函数2, 变量3 应该和上一条等效。
import 模块名 as 自定义名 和 python 一样。
Main,在最上层定义的名字(变量,函数等)都可以记为 Main.名字。
# module1.jl
module Module1
export function1 # 不 export 会怎样?
function function1()
println("This is function1 from Module1")
end
end
sin, size 等常用函数都是 Base 模块中的,Base 模块会自动导入到每个 session 所以可以省略。
parentmodule(sin) 可以查询 sin 函数所在的模块(Base)。
macro mymacro()
# 没有 return 则默认 return 最后的 quote 表达式
quote
println("The value of x is $x")
end
end
x = 3
@mymacro() # 打印 The value of x is 10
quote ... end 结构用于把若干命令打包成一个类型为 Expr 的对象,类型为 Expr。里面的内容不会立即执行。
quote ... end 也可以简写为 :( ... ),类型是 Expr,表示 Julia AST(详见 Julia 开发笔记)。
@mymacro,如果当前的 x 有定义就会打出它的值。
@macroexpand @mymacro 来查看宏展开后的代码。
# 类似一个普通函数
macro mymacro2(args...)
println("=== Macro called ===")
println("type of args: $(typeof(args))")
println("Number of arguments: $(length(args))")
for (i, arg) in enumerate(args)
println("Argument $i: $(string(arg)) | Type: $(typeof(arg))")
end
println()
return :(nothing)
end
x = 1; y = 2; z = 3
@mymacro2(x, y, z)
@mymacro2 x y z # 等效的调用方法
# 输出:
# === Macro called ===
# type of args: Tuple{Symbol, Symbol, Symbol}
# Number of arguments: 3
# Argument 1: x | Type: Symbol
# Argument 2: y | Type: Symbol
# Argument 3: z | Type: Symbol
也就是说,宏的入参会把所有变量当符号(或表达式)处理,不会考虑其值。
@mymacro2 x+y z
# 输出:
% === Macro called ===
% type of args: Tuple{Expr, Symbol}
% Number of arguments: 2
% Argument 1: x + y | Type: Expr
% Argument 2: z | Type: Symbol
Task(f) 开启协程执行函数 f。但用户基本从来不用这个。
I/O wait,2. yield(),3. 执行结束。
@async begin
for i in 1:3
println("A $i")
sleep(0.5)
end
end
@async begin
for i in 1:3
println("B $i")
sleep(0.5)
end
end
current_task() 可以得到当前 Task 对象。显示为 Task (runnable) @0x0...d7f0