贡献者: addis
参考 Julia 文档。
float, double 等不是对象,只有 struct, class 定义的才是对象。Julia 中的对象没有成员函数。
::变量类型 用于确认它具有该类型,如果类型不符会产生异常。如果 变量类型 是抽象的,那么表达式只能是它的一个子类。
常见类型
Int8, UInt8, Int16, UInt16, Int32, UInt32, Int64(即 Int), UInt64, Int128, UInt128, Float16, Float32, Float64, ComplexF16, ComplexF32 和 ComplexF64
BigInt 是任意大小的整数,BigFloat 是任意精度浮点数。
julia> BigFloat(2.1) # 2.1 here is a Float64
2.100000000000000088817...
julia> BigFloat("2.1") # the closest BigFloat to 2.1
2.099999999...99999986
julia> BigFloat("2.1", RoundUp)
2.100000000...0000021
julia> BigFloat("2.1", precision=128)
2.0999999...995
julia> BigFloat("2.1", RoundUp, precision=128)
2.100000000...00000000000007
使用 typeof(var) 来询问变量类型,用 isa(var, type) 来确定类型。sizeof(变量或类型) 来查看类型的字节数
setprecision(二进制精度); 可以设置运算默认的精度
BigFloat(pi) 会默认为上面设置的精度,BigFloat(pi, precision=...) 可以临时改变精度,但是 BigFloat(pi, precision=...)*2 仍然是上面设置的精度,因为乘法使用上面设置的精度。
pi 的加减乘除都得到 Float64 类型。
Bool 类型的值可以是 true 或者 false
any([true, false, ...]) 和 all([trua, false, ...])
typeof(3) 是 Int64;typeof(12345678902234567890) 是 Int128,typeof(1234567890223456789032345678904234567890) 是 BigInt。typemin(类型) 和 typemax(类型) 可以查看最大最小值。
a = Int8(1),a += 1 后 a 会变为 Int64。因为 1 相当于 Int64(1)。
Float64。
eps(Float64) 返回 2.220446049250313e-16
NaN 是 not a number,可以用 isnan(x) 来判断
:名字 表示任意名字的 Symbol,常用于字典的 key,类似于 C++ 的 enum。
Symbol(又例如 :abc,:a)注意 :pi 和 :π 是两个不同的 Symbol。
Symbol("#3ac!3f") 创建。
pi 的类型是 Irrational{:π} 其中 :π 的类型是
BigFloat(pi, precision=500) 可以获得 500 位二进制的 pi。
Char,字符串的类型是 String。
sizeof(Char) = 4
a = "你好 Julia" 中,a[1] 是 你,a[4] 是 好,a[8] 是 J。a[2] 会报错!
i = nextind(str, i) 来获取下一个字符的合法索引!
for c = str 也可以遍历每个字符(不是每个字节)
for i = eachindex(a) 可以遍历每个字符所在的索引
length(str) 返回字符个数(不是每个字节数)
s = "abcde" 的类型是 String,注意 String 并不是 Array{Char, 1}! s[i] 可以获取单个 Char,但是不能赋值,因为 String 是不可改变的(immutable)。
s1 = replace(s, "bc" => "BC")。s1 也可以是 s 本身。
s = s1*s2 拼接字符串(等效地:s = string(s1, s2)),s *= s1 可以 append。
string(str1, str2, ...) 也可以拼接
s = s1^3 重复字符串 3 次,s ^= 3 同理。相当于 repeat(s1, 3)
findfirst("abc", s) 搜索字符串,返回一个 UnitRange{Int64},如 3:5。
findnext("abc", s, ind) 从 ind 开始搜索下一个
collect(str) 可以得到一个字符数组,即 Vector{Char}。
s = b"abcABC123" 的类型是 Base.CodeUnits{UInt8, String},s[i] 的类型是 UInt8
bytes = Vector{UInt8}(str) 可以把字符串转换为字节。
str = raw"Hello\nJulia" 创建裸字符串(\n 不当作换行)
a[i] = 'b';
"""...""" 可以表示多行字符串
"The sum of $x and $y is $(x + y)."
== 或 < 对比两个字符串。
new_str = replace(str, "Julia" => "World") 可以替换字符串。
str1 = strip(str) 可以除去两边空格。
parts = split(str, ",") 可以拆分字符串。
str = join(parts, ", ") 可以组合。
startswith(str, key) 和 endswith(str, key)。
findfirst(str, key) 和 findlast(str, key)
str = "Hello, Julia!"; m = match(r"Julia", str) 正则表达式匹配
new_str = original_str[1:7] * insert_str * original_str[8:end]
声明抽象类型
abstract type 子类名 <: 母类名 end
声明后,可以用 类1 <: 类2 来判断是否符合该关系,返回一个 Bool。
用 supertype(类) 可以查看某个类的母类,subtypes(类) 可以查看所有子类。
例子
abstract type Number end
abstract type Real <: Number end
abstract type AbstractFloat <: Real end
abstract type Integer <: Real end
abstract type Signed <: Integer end
abstract type Unsigned <: Integer end
最高级的抽象类是 Any,这里的 Number 就是 Any 的子类。
以及
Complex{T<:Real} <: Number
Rational{T<:Integer} <: Real
Irrational{sym} <: AbstractIrrational
原始类型(primitive type)是由 bit 组成的具体类型。Julia 可以自定义原始类型。定义原始类型的格式为
primitive type 类名 比特数 end
primitive type 类名 <: 父类名 比特数 end
例如
primitive type Float16 <: AbstractFloat 16 end
primitive type Float32 <: AbstractFloat 32 end
primitive type Float64 <: AbstractFloat 64 end
primitive type Bool <: Integer 8 end
primitive type Char <: AbstractChar 32 end
primitive type Int8 <: Signed 8 end
primitive type UInt8 <: Unsigned 8 end
primitive type Int16 <: Signed 16 end
primitive type UInt16 <: Unsigned 16 end
primitive type Int32 <: Signed 32 end
primitive type UInt32 <: Unsigned 32 end
primitive type Int64 <: Signed 64 end
primitive type UInt64 <: Unsigned 64 end
primitive type Int128 <: Signed 128 end
primitive type UInt128 <: Unsigned 128 end
Array{类型,维数}。一维数组 Array{类型,1} 也记为 Vector{类型},不区分行和列;Array{类型,2} 也记为 Matrix{类型},区分行向量和列向量。
[1, 2] 和 [1; 2] 的类型都是 Array{Int64,1},但 [1 2] 的类型是 Array{Int64,2}
类型[1,2,3] 可以创建指定类型的数组。
append!(数组, 元素) 或者 push!(数组, 元素) 可以在列向量最后添加一个元素。
push!([1, 2, 3], 4, 5) 或者 append!([1, 2, 3], [4, 5])
类型[] 创建空数组
a = [1 2; 3 4] 得到 Array{Float64,2} 注意不能用逗号,但可以不写 ; 而使用换行。
[1, "abc", 1.2] 的类型是 Vector{Any}。
[2^i for i = 1:10] 可以用通项公式快速生成一个数组。
typeof(1:3) 是 UnitRange{Int64}。支持 T<:Real 元素类。如 UnitRange(3.3, 5.6)。
typeof(1:2:5) 是 StepRange{Int64, Int64}。
typeof(1.1:3) 和 typeof(1.1:2:5) 的类型都是 StepRangeLen{T,R,S,L}。它的 constructor 是 a = StepRangeLen(ref::R, step::S, len::L, [offset=1])。其中 T 是标量类型即 a[i] 的类型,R 是 ref 即 a[offset] 的类型,S 是 step 的类型,L 是元素个数 len 的类型。
push!(v, 元素) 可以在 Vector 后面增加一个元素,同时也会返回新的 v。pop!(v) 移除最后的元素,返回最后一个元素。
splice!(v, 3:5) 可以删除 v[3:5]
A .= 值 或者 fill!(v, 值) 可以把 v 的每个元素赋值。
a[:, j, :]
size(矩阵, 维度),元素个数 length()(相当于 Matlab 的 numel),isempty() 检查空矩阵,reverse() 元素倒序排序
findmax(), findmin() 找到矩阵的最大最小元素。
Array{Float64,2}(undef, 2, 3) 创建矩阵,矩阵元不初始化。
zeros(整数) 或 zeros(整数, 整数) 分别返回 Array{Float64,1} 和 Array{Float64,2}。也可以用 zeros(类型, 整数, 整数) 指定类型。
rand(N1, N2, ...) 或者 rand(类型, N1, N2, ...)。
hash(矩阵),类型为 UInt64。把运算结果的 hash 输出可以保证计算过程不被优化掉。事实上可以作用于任何对象(包括自定义类型)。
Int64
a[:, 1] 或者 a[1, :] 仍然得到 Array{Int64,2}
a[:, 1] = [3; 4] 可以修改 a 的值
a = b 是浅复制,a 改变了 b 也会改变(同一对象)。
a = copy(b) 是真复制,新生成一个对象。
a === b 来判断是否是同一对象。
b = a[:, 1] 也是真复制。
a 作为参数传给函数是 pass by reference,相当于 C 语言传递指针(有例外,见 Julia 的函数)
Float32[1, 4, 5]。
Any。例如 ["a", 1.23] 的类型就是 Vector{Any} 即 Array{Any, 1}
函数.(数组) 可以对数组内的每个元素分别作用,返回数组。例如 sin.([1,2,3])。sin([1,2,3]) 是错误的用法。
exp([1 2;3 4]) 是矩阵的指数,exp.([1 2;3 4]) 是逐个元素做指数。
collect(1:5) 可以把类似 range 的类型变为 Vector{} 类型。
v .+ 标量 可以把数组的每一个元素加上标量。如果用 + 会出错。同理也有 .+=。其他算符同理。
矩阵 .+ 行向量 可以对每一行都加行向量。
B = [A; A] 可以拼接矩阵
resize!(矢量, N) 可以用于改变矢量长度,已有的元素值不会改变,新增的元素不初始化。
A = reshape(数组, N1, N2, ...) 或者 A = reshape(数组, (N1, N2, ...)) 可以改变数组的形状甚至维度。但改变前后元素个数必须不变。注意 A 和 数组 共享内存,改变一个另一个也会变。
A' 是厄密共轭,转置再取共轭,相当于 conj(transpose(A))
maximum(v) 求最大值,maximum(A,2) 求第二个维度的最大值。
argmax(v) 同理,返回 index。
v = Core.svec(1, "a", :x) 创建一个简单矩阵,通常不被用户使用而在内核内部使用。可以用 v[i] 获取值,但不能改变(unmutable)
length(v) 检查长度
collect(v) 变为普通数组
a[:, 1] 作为参数传给函数是 pass by value,如果需要 by reference,使用 view 函数获取 SubArray 类
SubArray 不存数据,可以用来给函数参数 pass by reference
SubArray 类型的 5 个参数 SubArray{标量类,维数,矩阵类,Tuple{各维度索引类型},是否支持快速索引}
view(a, :, 1) 的类型是 SubArray{Int64,1,Matrix{Int64},Tuple{Base.Slice{Base.OneTo{Int64}},Int64},true}
view(a, 1, :) 的类型是 SubArray{Int64,1,Matrix{Int64},Tuple{Int64,Base.Slice{Base.OneTo{Int64}}},true}
view(a, 1:2, 2:3) 的类型是 SubArray{Int64,2,Matrix{Int64},Tuple{UnitRange{Int64},UnitRange{Int64}},false}
SubArray <: AbstractArray{T,Ndim} <: Any
Array{T,Ndim} <: DenseArray{T,Ndim} <: AbstractArray{T,Ndim} <: Any
AbstractArray,就可以同时接受 Array, SubArray。
SubArray 的结构
struct SubArray{T,N,P,I,L} <: AbstractArray{T,N}
parent::P
indices::I
offset1::Int # for linear indexing and pointer, only valid when L==true
stride1::Int # used only for linear indexing
...
end
1:5 等效于 range(1,5),类型是 UnitRange{Int64}
Vector(3:5)。
1:3:9 等效于 StepRange(1, 3, 9),类型是 StepRange{Int64, Int64} 注意 StepRange 类型的参数只能是整数。StepRange(1, Int8(3), 9) 的类型是 StepRange{Int64, Int8}
1.2:5.1(等效于 range(1.2,5.1))和 1:0.2:4.1(等效于 1:0.2:4 和 range(1,4,16))的类型是 StepRangeLen{Float64, Base.TwicePrecision{Float64}, Base.TwicePrecision{Float64}, Int64}。range(2,4,3) 虽然每个元素都是整数,但类型也是一样的。
LinRange(初始值,终止值,个数) 概念上是等间距数组,相当于 Matlab 的 linspace。但类型为 LinRange{Float64, Int64}。
range(1,2,length=3) 等效于 1.0:0.5:2.0。
AbstractRange <: AbstractVector <: Any,都可以像数组一样用 size(x, dim) 来获取尺寸,length() 获取元素个数,可以用 x[i] 获取元素。
复合类型(composite) 类似于 C++ 中的 struct,但是不能有成员函数。
struct Foo
bar # 抽象类型是 Any
baz::Int
qux::Float64
end
创建该类型的对象
foo = Foo("Hello, world.", 23, 1.5) # 叫做 constructor
foo.bar, foo.baz, foo.qux 等。用 struct 声明的复合类型值在生成后就不能被改变。如果 struct 里面有矩阵等,那么矩阵元仍然是 mutable 的(没有 lower level const)。
mutable struct 来声明即可。mutable struct 通常存在 heap 中而不是在 stack 中。
fieldnames(类型),如果还要显示成员类型,用 dump(Foo)。
getglobal(module::Module, name::Symbol, [order::Symbol=:monotonic]) 可以从模块中获取符号。
getproperty(a, b) 相当于算符 a.b。会根据 a, b 的类型调用 getglobal(::Module, ::Symbol),getfield(::Type, ::Symbol)(结构体获取字段),getfield(::Tuple, ::Int)(Tuple 获取元素)
isdefined(对象, :字段名) 可以判断对象的字段是否存在
ismutable(Foo) 可以判断是否 mutable struct。
? 进入 help 模式,然后再输入 Foo。等效地也可以用 @doc Foo。
struct Person
name::String
age::Int
function abc(name::String, age::Int, add::Int)
new(name, age+add)
end
end
Base.convert(::Type{类型1}, f::类型2),转换用 g = convert(类型1, f)
mutable struct User
id::Int
name::String
email::String
age::Int
end
user1 = User(1, "Alice", "alice@example.com", 30)
mutable,构造后将不能改变字段值。
fieldnames(类型) 查看所有字段,fieldname(类型, i) 查看第 i 个,nfields(对象) 是数量,fieldtypes(类型) 查看对应的类型。dump(类型) 查看详情,methods(类型) 查看有哪些函数(似乎只能显示构造函数)。
dump(Rational{Int64}) 得到
Rational{Int64} <: Real
num::Int64
den::Int64`
nfields(1//2) 得到 2。注意 nfields(Rational{Int64}) 是 8,因为 typeof(Rational{Int64}) 是 DataType,而 dump(DataType) 是
DataType <: Type{T}
name::Core.TypeName
super::DataType
parameters::Core.SimpleVector
types::Core.SimpleVector
instance::Any
layout::Ptr{Nothing}
hash::Int32
flags::UInt16
fieldnames(Rational{Int64}) 得到 (:num, :den),fieldtypes(Rational{Int64}) 得到 (Int64, Int64)。
C:\Users\addis\AppData\Local\Programs\Julia-1.11.6\share\julia\base\boot.jl):
struct Pair{A, B}
first::A
second::B
Pair(a, b) = new{typeof(a), typeof(b)}(a, b)
function Pair{A, B}(@nospecialize(a), @nospecialize(b)) where {A, B}
@inline
return new(a::A, b::B)
end
end
IntOrString = Union{Int, AbstractString}
1 :: IntOrString
"Hello!" :: IntOrString
1.0 :: IntOrString # 异常
但是,这和使用 <: 有什么区别?一个类只可能有一个非 Union 的母类,如果一个函数的参数想要支持两个母类不同的类怎么办?那就用 Union 即可。
另外一个应用的例子是 Union{T, Nothing} 作为函数参数,这样这个参数就可以忽略了。
复数类型 ComplexF16, ComplexF32 和 ComplexF64 是 Complex{Float16}, Complex{Float32} 和 Complex{Float64} 的别名。Complex 就是一个含参类型(parametric type)
例如
struct Point{T}
x::T
y::T
end
那么 Point{Float64} 等都是合法的具体类型。
Point 本身是一个抽象类,是其具体类的母类
julia> Point{Float64} <: Point
true
julia> Point{AbstractString} <: Point
true
<: 相当于一个二元算符,输出 Bool。
例子:
function norm(p::Point{Real})
sqrt(p.x^2 + p.y^2)
end
constructor
p = Point{Float64}(1.0, 2.0)
含参抽象类型(Parametric Abstract Types) 例如
abstract type Pointy{T} end
struct Point{T} <: Pointy{T}
x::T
y::T
end
值1 => 值2 的数据类型是 Pair{类型1, 类型2},两种类型都可以是 Any。
"abc" => 1.23 的类型是 Pair{String, Float64},令 p = "abc" => 1.23,那么 p.first 和 p.second 分别可以获取两个变量。
Pair 同样是 immutable 的。
Tuple 是函数参数列表的抽象。例如两个元素的 tuple type 类似于如下的含参 struct 类型
struct Tuple2{A,B}
a::A
b::B
end
例子
julia> typeof((1,"foo",2.5))
Tuple{Int64, String, Float64}
julia> Tuple{Int,AbstractString} <: Tuple{Real,Any}
true
julia> Tuple{Int,AbstractString} <: Tuple{Real,Real}
false
t = (值1, 值2, 值3, ...) 就是 Tuple
Tuple 的元素类型可以不同
t = (1, "3.1", [1 2; 3 4]) 的类型是 Tuple{Int64, String, Matrix{Int64}}
length(),isempty(),reverse() 同样适用于 Tuple。
t[i] 获取某个元素,但不能对其赋值! Tuple 的元素永远不能改变! Tuple 类型是 immutable 的。
x = (a=2, b="abc"),类型为 NamedTuple{(:a, :b), Tuple{Int64, String}}。然后可以使用 x.a 和 x.b 来获取元素。
(1,),空 tuple 用 () 表示,类型为 Tuple{}。
(a1,a2,a3) = my_tuple 可以把 Tuple 拆开
(x,y) = (1,"ab") 或者 x,y = (1,"ab") 会分别把元素赋值给 x, y。这可以用于函数返回多个值。
p = pointer(v) 可以获取一个数组第一个元素的指针,类型是 Ptr{元素类型}。unsafe_load(p) 可以获得第一个元素的值 p + sizeof(元素类型) 可以获得下一个元素的指针。
unsafe_store!(p, 值) 可以给指针的元素赋值。
Ref{类型} 创造一个安全的引用,保证类型不变,被引用的对象不会被回收。
ccall 调用 C 函数。
# immutable
x = 3
r = Ref(x) # Base.RefValue{Int64}(3)
println(r[]) # 解引用,打印 3
x = 4 # 不会改变 r[]
r[] = 2 # 不会改变 x
println("x = $x, r[] = $(r[])")
# 调用 C 函数
# ccall(:foo, Cvoid, (Ref{Int},), r)
# mutable
x = [1,2,3]
r = Ref(x) # Base.RefValue{Vector{Int64}}([1, 2, 3])
println(r[]) # 解引用,打印 [1, 2, 3]
x[1] = 4 # 会改变 r[]
r[][2] = 5 # 会改变 x
println("x = $x, r[] = $(r[])")
Set 是无序集合,若要有序,用 OrderedCollections.jl 中的 OrderedSet
s = Set{Int64}() 生成某种类型的空 set。
s = Set([1,2,3]) 把数组变为 Set(自动推导出类型 Set{Int64})
push!(s, 123, 23, 532) 添加若干元素。
empty!(s) 清空集合。
in(123, s) 查看某个元素是否存在
union!(s1,s2) 计算并集,赋值给 s1,s = union(s1,s2) 计算并集,赋值给 s。
d = Dict{key类型,Val类型}() 创建一个字典(哈希表),也可以直接用 Dict("ab"=>12, "bc"=>23)(会自动推导类型 Dict{String, Int64})
d = Dict("a" => 1, "b" => 2),取值用 d["a"],d["c"] 会报错,若不想报错也可以用 get(d, "c", nothing) 当 key 不存在就会返回第三个入参。
push!(d, key1=>val1, key2=>val2) 添加若干 entry,如果 key 已经存在,就覆盖 val。
a[key] = val。
a[key] 获取对应的 val,如果 key 不存在则会出错。
delete!(d, key)
keys(d) 表示所有存在的 key,类型是 Base.KeySet{key类型, Dict{key类型, val类型}},不会复制值。
vals(d) 同理,类型是 Base.ValueIterator{Dict{String, Int64}}
for (k, v) in d
...
end
使用等号。例如
# 32-bit system:
julia> UInt
UInt32
# 64-bit system:
julia> UInt
UInt64
实现方法
This is accomplished via the following code in base/boot.jl:
if Int === Int64
const UInt = UInt64
else
const UInt = UInt32
end
julia> isa(1, Int)
true
julia> typeof(Rational{Int})
DataType
julia> typeof(Union{Real,String})
Union
julia> typeof(DataType)
DataType
julia> typeof(Union)
DataType
julia> supertype(Float64)
AbstractFloat
julia> supertype(Number)
Any
julia> supertype(AbstractString)
Any
julia> supertype(Any)
Any
A = rand(2, 2); B = A.^2; 在 IR 中会翻译成如下代码
A = rand(2, 2);
# two 类型为单例类 Val{2},相当于执行 two=Val{2}() 或 Val(3)
two = (Core.apply_type(Base.Val, 2))()
expr = Base.broadcasted(Base.literal_pow, Main.:^, A, two)
B = Base.materialize(expr)
Core.apply_type(类模板, 模板参数 ...) 可以从模板创建一个类型,模板参数应该需要为编译时常量。
类() 或者 (类)() 调用默认构造函数。
Base.literal_pow(Main.:^, 3, Val{2}()) 可以计算 3^2 = 9
Base.broadcasted(算符或函数, 参数1, 参数2, ...) 其中 参数* 本身或者其矩阵元被传入 算符或函数。
Val{2} 的父类是 Any
 
 
 
 
 
 
 
 
 
 
 
友情链接: 超理论坛 | ©小时科技 保留一切权利