From c97f6a7bca228765b967b7f962e41fb425cd702f Mon Sep 17 00:00:00 2001 From: jaywcjlove <398188662@qq.com> Date: Mon, 14 Nov 2022 21:57:38 +0800 Subject: [PATCH] feat: add julia.md #59 --- README.md | 1 + docs/julia.md | 681 +++++++++++++++++++++++++++++++++++++++ scripts/assets/julia.svg | 2 + 3 files changed, 684 insertions(+) create mode 100644 docs/julia.md create mode 100644 scripts/assets/julia.svg diff --git a/README.md b/README.md index a71e436..f840c30 100644 --- a/README.md +++ b/README.md @@ -41,6 +41,7 @@ Quick Reference [INI](./docs/ini.md) [JSON](./docs/json.md) [Java](./docs/java.md) +[Julia](./docs/julia.md) [LaTeX](./docs/latex.md) [Markdown](./docs/markdown.md) [MySQL](./docs/mysql.md) diff --git a/docs/julia.md b/docs/julia.md new file mode 100644 index 0000000..394eaf5 --- /dev/null +++ b/docs/julia.md @@ -0,0 +1,681 @@ +Julia 备忘清单 +=== + +本备忘清单旨在快速理解 [Julia](https://mysql.com) 一份简单而粗略的语言概览,供您参考。 + +入门 +--- + +### Julia 是什么? + + +- **`Julia`** 是一种为科学计算而生的,开源、多平台、高性能的高级编程语言 +- **`Julia`** 有一个基于 LLVM 的 JIT 编译器,这让使用者无需编写底层的代码也能拥有像 C 与 FORTRAN 那样的性能。因为代码在运行中编译,你可以在 shell 或 REPL 中运行代码,这也是一种推荐的工作流程 +- **`Julia`** 是动态类型的。并且提供了为并行计算和分布式运算设计的多重派发机制 +- **`Julia`** 自带包管理器 +- **`Julia`** 有许多内置的数学函数,包括特殊函数 (例如:Gamma 函数)。并且支持开箱即用的复数运算 +- **`Julia`** 允许你通过类似 Lisp 的宏来自动生成代码 +- **`Julia`** 诞生于 2012 年 + +### 赋值语句 + +```julia +answer = 42 +x, y, z = 1, [1:10; ], "A string" +x, y = y, x # 交换 x, y +``` + +### 常量定义 + +```julia +const DATE_OF_BIRTH = 2012 +``` + +### 行尾注释 + +```julia +i = 1 # 这是一行注释 +# 多行注释 +#= 这是另一行注释 =# +``` + +### 链式操作 + +```julia +x = y = z = 1 # 从右向左 +0 < x < 3 # true +5 < x != y < 5 # false +``` + +### 函数定义 + +```julia +function add_one(i) + return i + 1 +end +``` + +### 插入 LaTeX 符号 + +```julia +\delta + [Tab] # δ +``` + +### 运算符 + + +:- | :- +:- | :- +基本算数运算 | `+`,`-`,`*`,`/` +幂运算 | `2^3` => 8 +除法 | `3/12` => 0.25 +反向除法 | `7\3 == 3/7` => true +取余 | `x % y` 或 `rem(x,y)` +取反 | `!true` => false +等于 | `a == b` +不等于 | `a != b` 或 `a ≠ b` +小于与大于 | `<` 与 `>` +小于等于 | `<=` 或 `≤` +大于等于 | `>=` 或 `≥` +逐元素运算(点运算) | `[1, 2, 3] .+ [1, 2, 3] == [2, 4, 6]` => true
`[1, 2, 3] .* [1, 2, 3] == [1, 4, 9]` => true +检测非数值(NaN) | `isnan(NaN)` => true
而不是 `NaN == NaN` => false +三元运算符 | `a == b ? "Equal" : "Not equal"` +短路 AND 和 OR 表达式 | `a && b` 和 `a \|\| b` +对象等价 | `a === b` + +### shell/REPL 环境 + + +:- | :- +:- | :- +上一次运算的结果 | `ans` +中断命令执行 | Ctrl + C +清屏 | Ctrl + L +运行程序文件 | `include("filename.jl")` +查找 func 相关的帮助 | `?func` +查找 func 的所有定义 | `apropos("func")` +命令行模式 | `;` +包管理模式 | `]` +帮助模式 | `?` +查找特殊符号输入方式 | `?☆ # "☆" can be typed by \bigwhitestar` +退出特殊模式,返回到 REPL | 在空行上按 Backspace +退出 REPL | `exit()` 或 Ctrl + D + +### 缺失值与空值 + +:- | :- +:- | :- +空值(Null) | `nothing` +缺失数据 | `missing` +浮点数的非数值 | `NaN` +滤除缺失值 | `collect(skipmissing([1, 2, missing])) == [1,2]` +替换缺失值 | `collect((df[:col], 1))` +检查是否有缺失值 | `ismissing(x)` 而不是 `x == missing` + +### 自我检查与反射 + +:- | :- +:- | :- +类型 | `typeof(name)` +类型检查 | `isa(name, TypeName)` +列出子类型 | `subtypes(TypeName)` +列出超类型 | `supertype(TypeName)` +函数方法 | `methods(func)` +即时编译的字节码 | `code_llvm(expr)` +汇编代码 | `code_native(expr)` + +### 随机数 + + +:- | :- +:- | :- +设置随机数种子 | `Random.seed!(seed)` +产生随机数 | `rand()` # 均匀分布 [0,1)
`randn()` # 正态分布 (-Inf, Inf) +产生特定分布的随机数 | `using Distributions`
`my_dist = Bernoulli(0.2)` 举例
`rand(my_dist)` +以概率 p 从 A 中进行伯努利抽样 | `randsubseq(A, p)` +随机重排 A 中的元素 | `shuffle(A)` + +许多随机数函数都需要 `using Random` + +### 异常处理 + + +```julia +# 抛出异常 SomeExcep +throw(SomeExcep()) +# 再次引发当前的异常 +rethrow() +``` + +定义新异常 NewExcep + +```julia +struct NewExcep <: Exception + v::String +end +Base.showerror(io::IO, e::NewExcep) = print(io, "A problem with $(e.v)!") + +throw(NewExcep("x")) +# 抛出带文本的异常 +error(msg) +``` + +异常处理流程 + +```julia +try + # 进行一些可能会失败的操作 + catch ex + if isa(ex, SomeExcep) + # 处理异常 SomeExcep + elseif isa(ex, AnotherExcep) + # 处理另一个异常 AnotherExcep + else + # 处理其余的异常 + end + finally + # 永远执行这些语句 +end +``` + +### 类型 + + +```julia +# 类型注释 +var::TypeName +# 类型声明 +struct Programmer + name::String + birth_year::UInt16 + fave_language::AbstractString +end +# 可变类型声明 +将 struct 替换为 mutable struct +# 类型别名 +const Nerd = Programmer +# 类型构造器 +methods(TypeName) +# 类型实例 +me = Programmer("Ian", 1984, "Julia") +me = Nerd("Ian", 1984, "Julia") +# 子类型声明 +abstract type Bird end +struct Duck <: Bird + pond::String +end +# 参数化类型 +struct Point{T <: Real} + x::T + y::T +end + +p = Point{Float64}(1,2) +# 联合类型 +Union{Int, String} +# 遍历类型层级 +supertype(TypeName) 和 subtypes(TypeName) +# 默认的超类型 +Any +# 所有字段 +fieldnames(TypeName) +# 所有字段类型 +TypeName.types +``` + +### 标准库 + +:- | :- +:- | :- +Random | `rand`, `randn`, `randsubseq` +Statistics | `mean`, `std`, `cor`, `median`, `quantile` +LinearAlgebra | `I`, `eigvals`, `eigvecs`, `det`, `cholesky` +SparseArrays | `sparse`, `SparseVector`, `SparseMatrixCSC` +Distributed | `@distributed`, `pmap`, `addprocs` +Dates | `DateTime`, `Date` + +### 表达式 + + +使用引用 `:( ... )` 或块引用 `quote ... end` 可以创建一个表达式,就像 `parse(str)`,和 `Expr(:call, ...)`。 + +```julia +x = 1 +line = "1 + $x" # 一些代码 +expr = Meta.parse(line) # 生成一个 Expr 对象 +typeof(expr) == Expr # true +dump(expr) # 打印生成抽象语法(AST) +eval(expr) == 2 # 对 Expr 对象求值: true +``` + +Julia 具有同像性:程序被表示为语言本身的数据结构。 实际上 `Julia` 语言里的任何东西都是一个表达式 `Expr`。符号(`Symbols`)即驻留字符串 ,以冒号 `:` 为前缀。相对于其他类型来说,符号效率更高。它也经常用作标识符、字典的键或者数据表里的列名。符号不能进行拼接。 + +### 输入/输出 + + +读取流 + +```julia +stream = stdin +for line in eachline(stream) + # 做点啥 +end +``` + +读取文件 + +```julia +open(filename) do file + for line in eachline(file) + # 做点啥 + end +end +``` + +读取/写入 CSV 文件 + +```julia +# 读取 CSV 文件 +using CSV +data = CSV.File(filename) +# 写入 CSV 文件 +[label](koajs.md)CSV.write(filename, data) +``` + +读取/保存 Julia 对象 + +```julia +using JLD +# 保存 Julia 对象 +save(filename, "object_key", object, ...) +# 读取 Julia 对象 +d = load(filename) # 返回对象的字典 +``` + +读取/保存 HDF5 + +```julia +using HDF5 +# 保存 HDF5 +h5write(filename, "key", object) +# 读取 HDF5 +h5read(filename, "key") +``` + +### 宏 + + +宏允许你在程序中自动生成代码(如:表达式) + +```julia +# 定义 +macro macroname(expr) + # 做点啥 +end +``` + +使用 + +```julia +macroname(ex1, ex2, ...) 或 @macroname ex1, ex2, ... +``` + + +内置的宏 + +```julia +@assert # assert (单元测试) +@which # 查看对特定参数使用的方法/查找函数所在的模块 +@time # 运行时间与内存分配统计 +@elapsed # 返回执行用时 +@allocated # 查看内存分配 +@async # 异步任务 + +using Test +@test # 精确相等 +@test x ≈ y # 近似相等 isapprox(x, y) + +using Profile +@profile # 优化 +``` + + +创建 卫生宏 (hygienic macros)的规则: + +- 在宏的内部只通过 `local` 声明本地变量 +- 在宏的内部不使用 `eval` +- 转义插值表达式以避免宏变大:`$(esc(expr))` + +### 并行计算 + + +并行计算相关的工具可以在标准库 `Distributed` 里找到 + +```julia +# 启动带 N 各 worker 的 REPL +julia -p N +# 可用的 worker 数量 +nprocs() +# 添加 N 个 worker +addprocs(N) +# 查看所有 worker 的 pid +for pid in workers() + println(pid) +end +# 获得正在执行的 worker 的 id +myid() +# 移除 worker +rmprocs(pid) +# 在特定 pid 的 worker 上运行 f(args) +r = remotecall(f, pid, args...) +# 或: +r = @spawnat pid f(args) +... +fetch(r) +# 在特定 pid 的 worker 上运行 f(args) (更高效) +remotecall_fetch(f, pid, args...) +# 在任意 worker 上运行 f(args) +r = @spawn f(args) ... fetch(r) +# 在所有 worker 上运行 f(args) +r = [@spawnat w f(args) for w in workers()] ... fetch(r) +# 让表达式 expr 在所有 worker 上执行 +@everywhere expr +# 并行化带规约函数 red 的循环 +sum = @distributed (red) for i in 1:10^6 + # 进行并行任务 +end +# 将 f 用用到集合 coll 中的所有元素上 +pmap(f, coll) +``` + + +### 数组 + + +:- | :- +:- | :- +声明数组 | `arr = Float64[]` +预分配内存 | `sizehint!(arr, 10^4)` +访问与赋值 | `arr = Any[1,2]`
`arr[1] = "Some text"` +从 m 到 n 的子数组 | `arr[m:n]` +n 个 `0.0` 填充的数组 | `zeros(n)` +n 个 `1.0` 填充的数组 | `ones(n)` +n 个随机 Int8 填充的数组 | `rand(Int8, n)` +用值 val 填充数组 | `fill!(arr, val)` +弹出最后一个元素 | `pop!(arr)` +弹出第一个元素 | `popfirst!(a)` +n 个 `#undef` 填充的数组 | `Vector{Type}(undef,n)` +n 个从 `start` 到 `stop` 的等间距数 | `range(start,stop=stop,length=n)` +将值 `val` 作为最后一个元素压入数组 | `push!(arr, val)` +将值 `val` 作为第一个元素压入数组 | `pushfirst!(arr, val)` +删除指定索引值的元素 | `deleteat!(arr, idx)` +数组排序 | `sort!(arr)` +将 `b` 连接到 `a` 后 | `append!(a,b)` +转化为字符串,并以 delim 分隔 | `join(arr, delim)` + + +--- + +```julia +# 数组比较 +a = [1:10;] +b = a # b 指向 a +a[1] = -99 +a == b # true +# 复制元素(而不是地址)/深拷贝 +b = copy(a) +b = deepcopy(a) +# 检查值 val 是否在数组 arr 中 +in(val, arr) # 或 +val in arr +# 改变维数 +reshape(1:6, 3, 2)' == [1 2 3; 4 5 6] +``` + +### 线性代数 + +:- | :- +:- | :- +单位矩阵 | `I` +定义矩阵 | `M = [1 0; 0 1]` +矩阵维数 | `size(M)` +选出第 i 行 | `M[i, :]` +选出第 j 列 | `M[:, j]` +水平拼接 | `M = [a b] 或 M = hcat(a, b)` +竖直拼接 | `M = [a ; b]` 或 `M = vcat(a, b)` +矩阵转置 | `transpose(M)` +共轭转置 | `M'` 或 `adjoint(M)` +迹(trace) | `tr(M)` +行列式 | `det(M)` +秩(rank) | `rank(M)` +特征值 | `eigvals(M)` +特征向量 | `eigvecs(M)` +矩阵求逆 | `inv(M)` +解矩阵方程 `M*x == v` | `M\v` 比 `inv(M)*v` 更好 +求 Moore-Penrose 伪逆 | `pinv(M)` + + +控制流与循环 +--- + +### 条件语句 + +```julia +if x < y + println("x is less than y") +elseif x > y + println("x is greater than y") +else + println("x is equal to y") +end +``` + +### for 循环 + +```julia +for i in 1:10 + println(i) +end +``` + +### 嵌套循环 + +```julia +for i in 1:10, j = 1:5 + println(i*j) +end +``` + +### 枚举 + +```julia +for (idx, val) in enumerate(arr) + println("the $idx-th element is $val") +end +``` + +### while 循环 + +```julia +while bool_expr + # 做点啥 +end +``` + +### 退出循环 + +```julia {4} +julia> i = 0 +julia> while true + global i += 1 + i > 5 && break + println(i) + end +``` + +### 退出本次循环 + +```julia {2} +for i = 1:6 + iseven(i) && continue + println(i) +end +``` + +数字相关 +--- + +### 整数类型 + +`IntN` 和 `UIntN`, 且 `N ∈ {8, 16, 32, 64, 128}`, `BigInt` + +### 浮点类型 + +`FloatN` 且 `N ∈ {16, 32, 64}` +`BigFloat` + +### 类型的最大和最小值 + +```julia +typemin(Int8) +typemax(Int64) +``` + +### 复数类型 + +```julia +Complex{T<:Real} +``` + +### 虚数单位 + +```julia +im +``` + +### 机器精度 + +```julia +eps() # 等价于 eps(Float64) +``` + +### 圆整 + +```julia +round() # 浮点数圆整 +round(Int, x) # 整数圆整 +``` + +### 类型转换 + +```julia +# 尝试进行转换/可能会报错 +convert(TypeName, val) +# 调用类型构造器转换 +TypeName(val) +``` + +### 全局常量 + +```julia +pi # 3.1415... +π # 3.1415... +im # real(im * im) == -1 +``` + +### 更多常量 + +```julia +using Base.MathConstants +``` + +模块 +--- + +### 定义 + +```julia +module PackageName +# 添加模块定义 +# 使用 export 让定义对外可见 +end +``` + +### 包含文件 filename.jl + +```julia +include("filename.jl") +``` + +### 加载 + + +```julia +using ModuleName # 导出所有名称 +# 仅导出 x, y +using ModuleName: x, y +# 仅导出 x, y +using ModuleName.x, ModuleName.y: +# 仅导出 ModuleName +import ModuleName +# 仅导出 x, y +import ModuleName: x, y +# 仅导出 x, y +import ModuleName.x, ModuleName.y +``` + +`using` 和 `import` 只有一点区别:使用 `using` 时,你需要写 `function Foo.bar(..` 来给 `Foo` 模块的函数 `bar` 增添一个新方法; 而使用 `import Foo.bar` 时,只需写 `function bar(...` 就能达到同样的效果 + +### 导出 + +```julia +# 得到模块导出名称的数组 +names(ModuleName) + +# 包含未导出的、弃用的 +# 和编译器产生的名称 +names(ModuleName, all::Bool) +# 也显示从其他模块显式导入的名称 +names(ModuleName, all::Bool, imported::Bool) +``` + + +包管理 +--- + +### 介绍 + +一个程序包必须先[注册](https://github.com/JuliaRegistries/General),然后才能在包管理器中看到它。在 Julia 1.0 中,有两种使用包管理器的方法: + +- 一是通过 `using Pkg` 导入 `Pkg` 模块,然后用它的函数管理其他包; +- 或者在 REPL 中输入 `]`,然后按回车。进入特殊的交互式包管理模式。 (要从包管理模式返回 REPL,只需要在空行上按退格键 `BACKSPACE` 就行了) + +注意新的工具总是先添加到交互式模式中,然后才会加入 `Pkg` 模块 + +### 在 Julia 会话中使用 Pkg 管理包 + +:- | :- +:- | :- +列出已安装的包 | `Pkg.status()` +更新所有包 | `Pkg.update()` +安装包 | `Pkg.add("PackageName")` +重新构建包 | `Pkg.build("PackageName")` +使用包 | `using PackageName` +删除包 | `Pkg.rm("PackageName")` + + +### 交互式包管理模式 + +:- | :- +:- | :- +添加包 | `add PackageName` +删除包 | `rm PackageName` +更新包 | `update PackageName` +使用开发版本 | `dev PackageName` 或 `dev GitRepoUrl` +返回普通发行版 | `free PackageName` + + +另见 +--- + +- [快速入门一份简单而粗略的语言概览](https://cheatsheet.juliadocs.org/zh-cn/) diff --git a/scripts/assets/julia.svg b/scripts/assets/julia.svg new file mode 100644 index 0000000..fd3637c --- /dev/null +++ b/scripts/assets/julia.svg @@ -0,0 +1,2 @@ + + \ No newline at end of file