类型操作
断言运算符::
::,作为运算符时语法:
左表达式::右数据类型,判断“左表达式”是否为“右数据类型”的实例,如果true,返回“左表达式”的值,如果false,返回错误信息。
true情况,例如
julia> (9.0*9.0) :: Float64
81.0
julia> (9*9) :: Int
81
julia> (9*9) :: Int64
81
julia> (9.0*9.0) :: Float64
81.0
julia> ("A") :: String
"A"
false情况,例如:
julia> (9*9) :: String
ERROR: TypeError: in typeassert, expected String, got Int64
Stacktrace:
[1] top-level scope at none:0
::在local变量时的使用
在代码块中赋值变量时,可以使用::做变量类型声明,语法:
变量名::类型 = 值
变量在赋值的同时声明类型,例如:
julia> function f_local()
x :: String = "this is function local string"
x
end
f_local (generic function with 1 method)
julia> f_local()
"this is function local string"
julia> typeof(ans)
String
对于返回值的类型,可以在函数定义时做出声明,例如上面f_local()这个函数还可以这样写:
julia> function f_local() :: String
x = "this is function local string"
x
end
f_local (generic function with 1 method)
julia> f_local()
"this is function local string"
julia> typeof(ans)
String
当在function之外,非local类型是,这样写是不符合语法的,错误信息中明确提示了,global类型是不能这么做类型声明的,例如:
julia> x :: String = "this is function local string"
ERROR: syntax: type declarations on global variables are not yet supported
上面这句,在特定条件下,可以写成local类型,例如:
julia> local x :: String = "this is function local string"
"this is function local string"
isa 函数
测试对象是否具有给定类型并返回 true 或 false:
julia> isa(123,Int64)
true
julia> isa(123,Float64)
false
typeof函数
返回其参数的类型:
julia> typeof(Float64)
DataType
julia> primitive type Ptr{T} 64 end
julia> typeof(Ptr)
UnionAll
julia> typeof(UnionAll)
DataType
supertype函数
返回类型的父类型:
julia> supertype(Int64)
Signed
julia> supertype(Float64)
AbstractFloat
julia> supertype(Any)
Any
抽象类型
抽象类型不能实例化,但它们是类型系统的主干。
Int8、UInt8、Int16、UInt16、Int32、UInt32、Int64、UInt64、Int128、UInt128、Float16、Float32 和 Float64,这些类型都不是抽象类型,它们是后面我们要介绍的原始类型。
声明抽象类型的语法:
abstract type «name» end
abstract type «name» <: «supertype» end
第一句没有“<: «supertype»”,系统默认它的父类型Any。
Julia系统内置抽象类型:
Number,Number下有Real,Real下有AbstractFloat和Integer,Integer下有Signed和Unsigned。
<: 运算符的通常意义为「是···的子类型」:
julia> Unsigned <: Number
true
julia> Unsigned <: Real
true
julia> Unsigned <: Integer
true
抽象类型允许程序员编写范型函数,之后可以通过许多具体类型将其用作对应的方法。
julia> mp(x,y) = x+y
mp (generic function with 1 method)
julia> mp(1,2)
3
julia> mp(1.1,2.2)
3.3000000000000003
原始类型
抽象类型可以实例化,Julia 允许声明自己的原始类型,且内置了大量的原始类型Int8、UInt8、Int16、UInt16、Int32、UInt32、Int64、UInt64、Int128、UInt128、Float16、Float32 和 Float64…………
声明抽象类型的语法:
primitive type «name» «bits» end
primitive type «name» <: «supertype» «bits» end
bits 的数值表示该类型需要多少存储空间,name 为新类型指定名称。
第一句没有“<: «supertype»”,系统默认它的父类型Any。
Julia类型的层级关系
Julia内部的数据类型按照层级分布,某些数据类型位于其他数据类型之上。
subtypes()返回作为参数传递的类型的子类型函数。
julia> function check_all_subtypes(T, space = 0)
println("\t" ^ space, T)
for t in subtypes(T)
if t != Any
check_all_subtypes(t, space+1)
end
end
end
check_all_subtypes (generic function with 2 methods)
julia> check_all_subtypes(Number)
Number
Complex
Real
AbstractFloat
BigFloat
Float16
Float32
Float64
AbstractIrrational
Irrational
Integer
Bool
Signed
BigInt
Int128
Int16
Int32
Int64
Int8
Unsigned
UInt128
UInt16
UInt32
UInt64
UInt8
Rational
julia> check_all_subtypes(AbstractString)
AbstractString
String
SubString
SubstitutionString
Test.GenericString
复合类型
复合类型是变量名域的集合。下例中,使用struct关键字,快速定义复合类型Person:
julia> struct Person
name::String
age::Int64
end
julia> Jack = Person("Jack",27)
Person("Jack", 27)
julia> typeof(Jack)
Person
julia> Jack.name
"Jack"
julia> Jack.age
27
可变复合类型
上面的复合类型的实例Jack,如果对Jack的名字做更改叫“Rose”:
julia> Jack.name = "Rose"
ERROR: type Person is immutable
Stacktrace:
[1] setproperty!(::Person, ::Symbol, ::String) at .\sysimg.jl:19
[2] top-level scope at none:0
有时有这样的需求,要求对对象的某个属性进行调整,这就引入了可变复合类型,关键字mutable。
julia> mutable struct Employee
name::String
age::Int64
end
julia> Boss = Employee("Jack",35)
Employee("Jack", 35)
julia> Boss.name = "Rose"
"Rose"
类型共用体
类型共同体内定义的类型,简单地理解,比Any少,比具体的原始类型又要多。这里的关键字是Union,不是Struct。
下面的点定义了类型共同体TypeMemo,只接受字符或字符串。当使用Int64类型与TypeMemo做匹配断言时,报错:
julia> TypeMemo = Union{Char, String}
Union{Char, String}
julia> "a" :: TypeMemo
"a"
julia> "abc" :: TypeMemo
"abc"
julia> 123 :: TypeMemo
ERROR: TypeError: in typeassert, expected Union{Char, String}, got Int64
Stacktrace:
[1] top-level scope at none:0
参数类型
类型可以接受参数,每一个参数值的可能组合引入一个新类型。
参数复合类型
下面代码定义了参数复合类型Point,在这里参数有两个x、y,为入参类型(泛型):
julia> struct Point{}
x::T
y::T
end
因为Point作为一个类型,下面每一个Point{T}都是它的子类型,所以:
julia> Point{Float64} <: Point
true
julia> Point{Int64} <: Point
true
julia> Point{String} <: Point
true
julia> Point{Char} <: Point
true
尽管Point的入参为Any类型,但是其他原始类型并非Point的子类型:
julia> Float64 <: Point
false
julia> Int64 <: Point
false
julia> String <: Point
false
julia> Char <: Point
false
Point下各个子类型相互间也没有层级关系:
julia> Point{Int64} <: Point{Real}
false
julia> Point{Float64} <: Point{Real}
false
julia> Point{String} <: Point{Any}
false
参数复合类型Point的实例化和引用格式:
julia> struct Point{T1,T2}
x::T1
y::T2
end
julia> function product(p::Point{<: Float64})
p.x * p.y
end
fc (generic function with 1 method)
julia> product(Point(1.1,2.2))
2.4200000000000004
接上面的代码,如果复合类型在引用时Point{Real}格式,将不包含Float64类型,所以:
julia> function product1(p::Point{Real})
p.x * p.y
end
fc (generic function with 1 method)
julia> product1(Point(1.1,2.2))
ERROR: MethodError: no method matching no(::Point{Float64,Float64})
Closest candidates are:
no(::Point{Real,T2} where T2) at none:2
为了包括包含Float64类型,使用<:运算符
julia> function product2(p::Point{<:Real})
p.x * p.y
end
fc (generic function with 1 method)
julia> product1(Point(1.1,2.2))
julia> product2(Point(1.1,2.2))
2.4200000000000004
复合类型Point,可以按照构造函数的形式,定义T1、T2的类型:
julia> Point(1,2)
Point{Int64,Int64}(1, 2)
julia> Point(1.2,2.3)
Point{Float64,Float64}(1.2, 2.3)
julia> Point(1.2,2)
Point{Float64,Int64}(1.2, 2)
😎参数复合类型定义可以使用mutable关键字,具体用法可以参考可变复合类型章节。
元组类型
元组和数组很像。
开数组并推数:
data =[]
push!(data,111)
push!(data,"222")
push!(data,333.33)
julia> println(data)
Any[111, "222", 333.33]
julia> typeof(data)
Array{Any,1}
julia> data[1] = 7788
7788
定义元组:
a = (111,"222",333.33)
julia> println(a)
(111, "222", 333.33)
julia> typeof(a)
Tuple{Int64,String,Float64}
julia> a[1] = 7788
ERROR: MethodError: no method matching setindex!(::Tuple{Int64,String,Float64},
::Int64, ::Int64)
😎从上例可以看出,数组和元组相似,同一数组或者元组内元素类型可以各不相同,下标都是从1开始,不同点在于数组可以通过下标访问并重新赋值,元组可以通过下标访问,但是不能重新赋值。
变参元组类型
关键字Tuple、Vararg,表示该类型元素数量不定。
julia> mulittuple = Tuple{String,Vararg{Int}}
Tuple{String,Vararg{Int64,N} where N}
julia> isa(("1",),mulittuple)
true
julia> isa(("1",123),mulittuple)
true
julia> isa(("1",123,2,3,4,5,6),mulittuple)
true
julia> isa(("1",123,2,3,4,5,6,7.7),mulittuple)
false
具名元组类型
就是带参数名的元组。
下面元组实例时的a\b\c就是参数名。
julia> x = (a=1,b=2.2,c="abc")
(a = 1, b = 2.2, c = "abc")
julia> typeof(x)
NamedTuple{(:a, :b, :c),Tuple{Int64,Float64,String}}
单态类型
简单地说,Type(T)的实例就是T。
julia> isa(Float64,Type{Float64})
true
julia> isa(Float64,Type{Real})
false
又因为,Type不带参数时,所有类型对象都是它的实例,当然也包括单态类型:
julia> isa(Float64,Type)
true
julia> isa(String,Type)
true
参数化原始类型
primitive type 为关键字,T为类型参数,例如在64位操作系统,可以声明:
primitive type Ptr{T} 64 end
不同的T表示不同的Ptr类型,尽管都叫Ptr,但是不同类型间无父子关系,所以:
julia> primitive type Ptr{T} 64 end
julia> Ptr{Int64} <: Ptr
true
julia> Ptr{Real} <: Ptr
true
julia> Ptr{Signed} <: Ptr
true
julia> Ptr{Int64} <: Ptr{Signed}
false
julia> Ptr{Int64} <: Ptr{Real}
false
julia> Ptr{Signed} <: Ptr{Real}
false
primitive type类型可以理解为C里的指针,Ptr{Int64}近似于int*,Ptr{Float64}近似于double*。
类型的别名
类型可以定义别名,通过1.0版本中,通过const关键字实现:
julia> const myint = Int64
Int64
julia> myint
Int64
在这里,myint是Int64的别名。
typeof 获得类型
supertype获得某个类型的父类型
eltype获得某个数集的元素类型
网友评论