Julia 学习笔记(一) | 数据类型和函数
Julia 笔记系列:
- 『Julia 基本使用及安装教程』
- 『Julia 学习笔记(一) | 数据类型和函数』
- 『Julia 学习笔记(二) | 类型,派发与设计模式』
- 『Julia 学习笔记(三) | 广播,性能和模块』
- 『Julia 学习笔记(四) | 并行计算(预备篇)』
- 『Julia 学习笔记(番外) | 从 Python 到 Julia』
唠唠闲话
本篇介绍 Julia 的基本语法,对应课程第二讲,主要内容如下:
Ps:这是关于 @陈久宁 在华东师范大学内部做的 Julia 系列讲座。课程 GitHub 地址 及第一讲Julia 概述。
Julia 的交互模式
概览
本节介绍 Julia 的五种交互模式,并重点介绍包管理模式,这五种模式分别为:
模式 | 说明 | 进入方式 |
---|---|---|
Julian 模式 | 执行 Julia 代码的地方 | 默认模式,在其他模式下通过退格键 Backspace 进入 |
Pkg 模式 | Julia 装包时使用的模式 | 在 Julian 模式按 ] 进入 |
Help 文档模式 | 查询文档时使用 | 在 Julian 模式下按 ? 进入 |
Shell 模式 | 切换到系统命令行 | 在 Julian 模式下按 ; 进入 |
Debug 模式 | 进入到代码调试模式 | 安装 Debugger.jl 后使用 |
经常用到且必须知晓的三个模式是 Julian 模式, Pkg 模式和 Help 模式。
基本介绍
-
首先在终端运行 Julia ,页面显示如下
-
初始进入 Julia 时,显示的模式就是 Julian 模式,左侧是绿色的
julia>
-
在 Julian 模式下,按下
]
进入 Pkg 模式(包管理模式),如下图
-
在任意模式下,按退格键(键盘上的
Backspace
)可以回到 Julian 模式 -
在 Julian 模式下,按下
?
进入 Help 模式,此时输入函数可以查看使用文档
-
在 Julian 模式下,按下
;
进入 Shell 模式,这个接触过 Linux 的应该懂怎么用 -
Debug 模式个人目前用得不多,暂略。
包的安装
Julia 中安装工具包的方法很简单,有两种方式,一是使用 Pkg
模式,二是在 Julian 模式下调用 Pkg
模块
-
方法一,输入
]
进入 Pkg 模式,如下图,左侧括号显示 Julia 的开发环境,@v1.6
代表 Julia 1.6 版本,使用默认环境
-
输入
add <包名称>
安装具体模块,比如下图,模块的下载目录在用户主目录的.julia
下
-
方法二,退格回到 Julian 模式,输入
using Pkg
导入包管理模块,再输入Pkg.add("<包名称>")
安装模块,如下图,注意包名称要用引号包含起来
-
包安装完成后,可以用
using <包名称>
测试模块导入
上边只涉及了 Pkg.add
命令,包管理还有很多常用命令,后续再单独写篇介绍,推荐阅读:Pkg 官方手册,Julia 读文档之包的实战
Julia 的数据结构
基本语法
Julia 用 #
代表注释,方便起见,相关知识点写在代码注释中
-
@xxx
为 宏(macro)的语法,宏可以实现“利用代码生成代码”。 -
演示常用的两种宏
@show
显示运算信息,式子间用<空格>
隔开@info
类似@show
,以第一个变量为打印信息
-
示例:
1
2
3
4x,y = 1,2
# x + y = 3 x+y
# x + y = 3 \n x - y = -1 x+y x-y
"记录信息" x y x+y显示结果
数据类型
-
整型,浮点数类型
1
2
3
4x = 1
# 默认整型 typeof(x)
λ = .1
# .1 等同于 0.1 typeof(λ)输出内容
-
Julia 支持使用 LaTeX ,比如 通过
\lambda
+<TAB>
输入;下标 通过c\_i
+<TAB>
输入。 -
Julia 中“数值 * 变量”用连接简记,比如
2x
等同于2 * x
-
其他数值类型
1
2
3
4
5
6
7
8
9
101+im) # im 代表虚数 i typeof(
1.0+2im) # 浮点虚数 typeof(
1 / 0 # 无穷大
0 * Inf # 不定数
Inf) # Float64 typeof(
NaN) # Float64 typeof(
pi) # 无理数 typeof(
missing) # 缺失类型,用于统计 typeof(
2 * missing # missing
nothing) # 相当于 Python 的None typeof(输出内容
-
字符相关
1
2
3
4
5
6
7
8
9
10'c') # 单引号代表字符 typeof(
"c") # 双引号代表字符串 typeof(
'c' == "c" # 数据结构不同
"c"[1] === 'c' # 字符串用索引取出的数据类型是字符
"c"[:] == 'c' # 切片取出字符串
"hello " * "world" # 字符串拼接用 *
"hi" ^ 3 # 字符串复制用 ^
var = 2333
"hello $var" # 使用 $ 插入实际变量
"hello $(var/10)" # h插入运算结果输出内容
-
字符转数值,要用
parse
,不能直接用Int
或Float64
1
2Int,"1") # Int 类型 parse(
Float64,"1") # Float 类型 parse(
容器数据类型
-
使用
[]
得列向量Vector
1
2
31, 2, 3] # Vector (column vector) x = [
# 等同于 Array{Int64, 1} typeof(x)
Vector(3:5) # Vector(3:5) = [3, 4, 5] -
切片规则:左闭右闭,首位索引为1,末位索引为
end
1
2
3
4x = [1,2,3]
1:end-1] # end-1 倒数第二位置 x[
# 取全部 x[:]
# 切片创建了新对象 x[:] === x
切片两端留空代表取全部,此时得到的是新对象;和 Python 不同的一点是,切片不能只写一侧,比如x[2:]
-
常用属性
size(x)
: 尺寸,Tuple{Int64}
类型length(x)
: 长度,类似 Python 的len
eltype(x)
: 元素类型
-
矩阵
1
2
3
4
5
6
7
8
9
101 2 3] # 空格分列,分号换行 y = [
1 2 3 4; 5 6 7 8] [
1 2 3 4 [
5 6 7 8] # 支持用换行号换行
# 行向量为矩阵类型 typeof(y)
# 矩阵形状 size(y)
# 列向量形状 size(x)
# false | 矩阵尺寸不同,返回否 x == y
# 向量转置,数据格式化为矩阵,类型相等 x' == y
# x 仍是向量,y 是 3*1 矩阵 y' == x -
元组(不可变类型)
1
2
3
4
5x = (1,2,3.)
# 元组会单独记录每个位置的数据结构 typeof(x)
1, 2, 3. # 定义时括号可省 x =
1,2 # 同 Python 的拆包功能 x,y =
1, 2, 3, 4, 5 # 拆包多余部分被丢弃 x, y = -
编译器足够聪明,元组的拆分组合操作运行很快
1
2
3modify_first!(t::Tuple, x) = (x, t[2:end]...)
t = (1, 2, 3)
0) modify_first!($t, -
容器内,使用
...
可将序列打开1
2x = [1,2,3]
0, x[2:end]...) [3,x...] ( -
字典
注意:初始化后,字典键值类型确定,此时新键值必须保持类型。1
2
3
4
5
6
7
8
9
10# Dict{Any, String} with 3 entries
d = Dict(1 => "item1",
"2" => "item2",
(3, 4) => "item3-4") # 创建字典
1] # 取出元素 d[
d[3] = "item3" # 新增键值
# d[2] = 2 # 报错,与字符串类型不符
1=>2) # 创建使用了 Pair 类型 typeof(
items = (x=>x^2 for x in 1:5) # 先创建 Pair
Dict(items) # 再生成字典 d = -
命名元组,可简单理解成不可变的字典类型
1
2
3
4
5d = (x = "first item",
y = "second item")
# 命名元组 typeof(d)
# 使用 Symbol 取出元素 d[:x]
# 使用 . 取出函数 d.y注意键名必须是变量,不能为数值之类
-
集合交并补操作
1
2
3
4
5x = [1, 2, 3]
y = [2, 3, 4]
# setdiff(x, y) = [1] setdiff(x, y)
# union(x, y) = [1, 2, 3, 4] union(x, y)
# intersect(x, y) = [2, 3] intersect(x, y) -
列表生成器和迭代器,和 Python 类似
1
2"列表生成器" [i for i in -0.5:0.2:1 ]
"迭代器" (i for i in -0.5:0.2:1 ) -
迭代器不需要创建中间变量来存储所有结果,在内存使用上是比较高效
1
2
3
4
5clamp(x, lo=0, hi=1) = x < lo ? lo : x > hi ? hi : x
f_list() = Dict([x => clamp(x) for x in -0.5:0.2:1.5])
f_generator() = Dict((x => clamp(x) for x in -0.5:0.2:1.5))
# 使用列表生成器 f_list()
# 使用迭代器 f_generator()
Julia 的函数
基本使用
-
用关键字
function
定义函数1
2
3
4
5# 如果没有 return ,默认返回最后一个变量
function f(x,y)
tmp = x + y
return tmp
end -
用单行定义函数
f(x,y) = x + y
-
三元表达式
cond ? true_rst : false_rst
,注意?
和:
前后要留空格1
2greater(a,b)= a>b ? true : false
1,2) greater( -
用
=
预定义参数值1
2f(x,y=10) = x+y # 用等号预定义
1) f(1,2) # 使用预定义 f(
注意:和 Python 不同的是,Julia 函数的默认值发生在函数调用时,所以如果预定义值为可变对象,下次调用将重新创建,而不必担心被修改。 -
函数指定参数类型,类似 C++ 的重载
1
2
3
4f(x::Tuple) = "input tuple"
f(x::Int) = "input int"
1,2)) # 输入元组 f((
1) # 输入整型 f( -
可变参数用
...
,类似 Python 的*
1
2
3f(x,y...) = y # 定义函数
1) # 可变参为空元组 f(
1,2,3,4) f( -
关键词参数
1
2
3
4
5f(x;y,z=10) = x + y + z # 分号隔开关键字
0,y=2) # z 取默认值,y 用关键值赋值 f(
# f(1,2,3) # 报错,必须用关键字赋值
f(x) = 0 # 函数重载只比对关键字前的部分
0) # 函数被重置 f( -
当函数修改变量信息时,约定上,函数名末尾追加
!
1
2
3
4
5x = [2,1]
sort(x)
# x 不变 x
sort!(x)
# x 改变 x
Julia 编写函数时,可以写两个版本,一个带!
允许修改变量,运算速度快;再写一个不带!
的版本,通过调用第一个函数来定义。
函数式编程
一等公民
在 Julia 的语言中,函数是“一等公民”(First-class citizen)。编程语言中,所谓一等公民,是指支持所有操作的实体, 这些操作通常包括作为参数传递,从函数返回,修改并分配给变量等。比如 int 类型,它支持作为参数传递,可以从函数返回,也可以赋值给变量,因此它是一等公民。类似的,函数是一等公民,意味着可以把函数赋值给变量或存储在数据结构中,也可以把函数作为其它函数的参数或者返回值。一般来说,函数式编程语言、动态语言和现代的编程语言,函数都会作为一等公民(参考 CSDN)。
Julia 与函数式编程
-
Julia 里的符号可以当函数来用,比如
1
1,2) # 相当于 1 + 2 +(
-
高阶函数
1
2
3f = x->x^2 # | 匿名函数
map(f,1:5) # [1,2,3,4,5] | 函数作用在右侧数据上,返回向量
map((x,y)->x+y,1:5,6:10) # [7,9,11,13,15] | 二元函数支持输入值为函数的还有
reduce
,mapreduce
,foreach
,sum
,filter
等。这部分和 MMA 类似,就不仔细介绍了。 -
do
创建一个匿名函数并将其作为第一个参数传递给函数调用1
2
3
4
5
6
7
8map(1:5) do x
return x^2
end
# 相当于
function f(x)
return x^2
end
map(f,1:5)
面向对象
和 Mathematica 一样,Julia 不支持面向对象,不能继承方法。但面向对象的很多功能,可以用结构体及多重派发替代。
可补充
- homework
- 函数式编程