鍍金池/ 教程/ Java/ 類型
類型轉(zhuǎn)換和類型提升
方法
嵌入式 Julia
交互
調(diào)用 C 和 Fortran 代碼
類型
代碼性能優(yōu)化
多維數(shù)組
元編程
函數(shù)
簡介
線性代數(shù)
與其它語言的區(qū)別
數(shù)學運算和基本函數(shù)
構(gòu)造函數(shù)
控制流
常見問題
并行計算
擴展包
開發(fā)擴展包
開始
字符串
運行外部程序
變量的作用域
模塊
網(wǎng)絡和流
代碼樣式
復數(shù)和分數(shù)
可空類型
整數(shù)和浮點數(shù)
變量
日期和時間

類型

Julia 中,如果類型被省略,則值可以是任意類型。添加類型會顯著提高性能和系統(tǒng)穩(wěn)定性。

Julia 類型系統(tǒng)的特性是,具體類型不能作為具體類型的子類型,所有的具體類型都是最終的,它們可以擁有抽象類型作為父類型。其它高級特性有:

  • 不區(qū)分對象和非對象值:Julia 中的所有值都是一個有類型的對象,這個類型屬于一個單一、全連通類型圖,圖中的每個節(jié)點都是類型。
  • 沒有“編譯時類型”:程序運行時僅有其實際類型,這在面向?qū)ο缶幊陶Z言中被稱為“運行時類型”。
  • 值有類型,變量沒有類型——變量僅僅是綁定了值的名字而已。
  • 抽象類型和具體類型都可以被其它類型和值參數(shù)化。具體來講, 參數(shù)化可以是 符號, 可以是 isbits 返回值為 true 的類型任意值 (本質(zhì)想是講, 這些數(shù) 像整數(shù)或者布爾值一樣, 儲存形式類似于 C 中的數(shù)據(jù)類型或者 struct, 并且 沒有指向其他數(shù)據(jù)的指針), 也可以是元組。如果類型參數(shù)不需要被使用或者 限制, 可以省略不寫。

Julia 的類型系統(tǒng)的設(shè)計旨在有效及具表現(xiàn)力,既清楚直觀又不夸張。許多 Julia 程序員可能永遠不會覺得有必要去明確地指出類型。然而某些程序會因聲明類型變得更清晰,更簡單,更迅速及健壯。

類型聲明

:: 運算符可以用來在程序中給表達式和變量附加類型注釋。這樣做有兩個理由:

  1. 作為斷言,幫助確認程序是否正常運行
  2. 給編譯器提供額外類型信息,幫助提升性能

:: 運算符放在表示值的表達式之后時讀作“前者是后者的實例”,它用來斷言左側(cè)表達式是否為右側(cè)表達式的實例。如果右側(cè)是具體類型,此類型應該是左側(cè)的實例。如果右側(cè)是抽象類型,左側(cè)應是一個具體類型的實例的值,該具體類型是這個抽象類型的子類型。如果類型斷言為假,將拋出異常,否則,返回左值:

    julia> (1+2)::FloatingPoint
    ERROR: type: typeassert: expected FloatingPoint, got Int64

    julia> (1+2)::Int
    3

可以在任何表達式的所在位置做類型斷言。 :: 最常見的用法是作為一個在函數(shù)/方法簽名中的斷言,例如 f(x::Int8) = ... (查看方法)。

:: 運算符跟在表達式上下文中的變量名后時,它聲明變量應該是某個類型,有點兒類似于 C 等靜態(tài)語言中的類型聲明。賦給這個變量的值會被 convert 函數(shù)轉(zhuǎn)換為所聲明的類型:

    julia> function foo()
             x::Int8 = 1000
             x
           end
    foo (generic function with 1 method)

    julia> foo()
    -24

    julia> typeof(ans)
    Int8

這個特性用于避免性能陷阱,即給一個變量賦值時意外更改了類型。

“聲明”僅發(fā)生在特定的上下文中:

    x::Int8        # a variable by itself
    local x::Int8  # in a local declaration
    x::Int8 = 10   # as the left-hand side of an assignment

并適用于整個當前范圍,甚至在聲明之前。目前,聲明類型不能用于全局范圍,例如在 REPL 中就不可以,因為 Julia 還沒有定型的全局變量。需要注意的是在函數(shù)返回語句中,上述的前兩個表達式計算值,還有就是 :: 是一個類型的斷言不是一個聲明。

抽象類型

抽象類型不能被實例化,它組織了類型等級關(guān)系,方便程序員編程。如,編程時可針對任意整數(shù)類型,而不需指明是哪種具體的整數(shù)類型。

使用 abstract 關(guān)鍵字聲明抽象類型:

    abstract ?name?
    abstract ?name? <: ?supertype?

abstract 關(guān)鍵字引入了新的抽象類型,類型名為 ?name? 。類型名后可跟 <: 及已存在的類型,表明新聲明的抽象類型是這個“父”類型的子類型。

如果沒有指明父類型,則父類型默認為 Any ——所有對象和類型都是這個抽象類型的子類型。在類型理論中,Any 位于類型圖的頂峰,被稱為“頂”。Julia 也有預定義的抽象“底”類型,它位于類型圖的最底處,被稱為 None。NoneAny 對立:任何對象都不是 None 的實例,所有的類型都是 None 的父類型。

下面是構(gòu)造 Julia 數(shù)值體系的抽象類型子集的具體例子:

    abstract Number
    abstract Real     <: Number
    abstract FloatingPoint <: Real
    abstract Integer  <: Real
    abstract Signed   <: Integer
    abstract Unsigned <: Integer

<: 運算符意思為“前者是后者的子類型”,它聲明右側(cè)是左側(cè)新聲明類型的直接父類型。也可以用來判斷左側(cè)是不是右側(cè)的子類型:

    julia> Integer <: Number
    true

    julia> Integer <: FloatingPoint
    false

抽象類型的一個重要用途是為具體的類型提供默認實現(xiàn)。舉個簡單的例子:

  function myplus(x, y)
      x + y
  endof

第一點需要注意的是, 上面的參數(shù)聲明等效于 x::Anyy::Any. 當這個函數(shù)被調(diào)用時, 例如 myplus(2, 5), Julia 會首先查找參數(shù)類型匹配的 myplus 函數(shù). (關(guān)于多重分派的詳細信息請參考下文.) 如果沒有找到比上面的函數(shù)更相關(guān)的函數(shù), Julia 根據(jù)上面的通用函數(shù)定義并編譯一個 myplus 具體函數(shù), 其參數(shù)為兩個 Int 型變量, 也就是說, Julia 會定義并編譯:

  function myplus(x::Int, y::Int)
      x + y
  end

最后, 調(diào)用這個具體的函數(shù)。

因此, 程序員可以利用抽象類型編寫通用的函數(shù),然后這個通用函數(shù)可以被許多具體的類型組合調(diào)用。也正是由于多重分派,程序員可以精確的控制是調(diào)用更具體的還是通用的函數(shù)。

需要注意的一點是, 編寫面向抽象類型的函數(shù)并不會帶來性能上的損失,因為每次調(diào)用函數(shù)時,根據(jù)不同的參數(shù)組合,函數(shù)總是要重新編譯的。(然而, 如果參數(shù)類型為包含抽象類型的容器是, 會有性能方面的問題;參見下面的關(guān)于性能的提示。)

位類型

位類型是具體類型,它的數(shù)據(jù)是由位構(gòu)成的。整數(shù)和浮點數(shù)都是位類型。標準的位類型是用 Julia 語言本身定義的:

    bitstype 16 Float16 <: FloatingPoint
    bitstype 32 Float32 <: FloatingPoint
    bitstype 64 Float64 <: FloatingPoint

    bitstype 8  Bool <: Integer
    bitstype 32 Char <: Integer

    bitstype 8  Int8     <: Signed
    bitstype 8  Uint8    <: Unsigned
    bitstype 16 Int16    <: Signed
    bitstype 16 Uint16   <: Unsigned
    bitstype 32 Int32    <: Signed
    bitstype 32 Uint32   <: Unsigned
    bitstype 64 Int64    <: Signed
    bitstype 64 Uint64   <: Unsigned
    bitstype 128 Int128  <: Signed
    bitstype 128 Uint128 <: Unsigned

聲明位類型的通用語法是:

    bitstype ?bits? ?name?
    bitstype ?bits? ?name? <: ?supertype?

?bits? 表明類型需要多少空間來存儲,?name? 為新類型的名字。目前,位類型的聲明的位數(shù)只支持 8 的倍數(shù),因此布爾類型也是 8 位的。

Bool, Int8Uint8 類型的聲明是完全相同的,都占用了 8 位內(nèi)存,但它們是互相獨立的。

復合類型

復合類型也被稱為記錄、結(jié)構(gòu)、或者對象。復合類型是變量名域的集合。它是 Julia 中最常用的自定義類型。在 Julia 中,所有的值都是對象,但函數(shù)并不與它們所操作的對象綁定。Julia 重載時,根據(jù)函數(shù) 所有參數(shù)的類型,而不僅僅是第一個參數(shù)的類型,來選取調(diào)用哪個方法(詳見 :方法 )。

使用 type 關(guān)鍵字來定義復合類型:

    julia> type Foo
             bar
             baz::Int
             qux::Float64
           end

構(gòu)建復合類型 Foo 的對象:

    julia> foo = Foo("Hello, world.", 23, 1.5)
    Foo("Hello, world.",23,1.5)

    julia> typeof(foo)
    Foo (constructor with 2 methods)

當一個類型像函數(shù)一樣被調(diào)用時,它可以被叫做類型構(gòu)造函數(shù)(constructor)。每個類型有兩種構(gòu)造函數(shù)是自動被生成的(它們被叫做默認構(gòu)造函數(shù))。第一種是當傳給構(gòu)造函數(shù)的參數(shù)和這個類型的字段類型不一一匹配時,構(gòu)造函數(shù)會把它的參數(shù)傳給 convert 函數(shù),并且轉(zhuǎn)換到這個類型相應的字段類型。第二種是當傳給構(gòu)造函數(shù)的每個參數(shù)和這個類型的字段類型都一一相同時,構(gòu)造函數(shù)直接生成類型。要自動生成兩種默認構(gòu)造函數(shù)的原因是:為了防止用戶在聲明別的新變量的時候不小心把構(gòu)造函數(shù)給覆蓋掉。

由于沒有約束 bar 的類型,它可以被賦任意值;但是 baz 必須能被轉(zhuǎn)換為 Int

    julia> Foo((), 23.5, 1)
    ERROR: InexactError()
     in Foo at no file

你可以用 names 這個函數(shù)來獲取類型的所有字段。

    julia> names(foo)
    3-element Array{Symbol,1}:
     :bar
     :baz
     :qux

獲取復合對象域的值:

    julia> foo.bar
    "Hello, world."

    julia> foo.baz
    23

    julia> foo.qux
    1.5

修改復合對象域的值:

    julia> foo.qux = 2
    2.0

    julia> foo.bar = 1//2
    1//2

沒有域的復合類型是單態(tài)類型,這種類型只能有一個實例:

    type NoFields
    end

    julia> is(NoFields(), NoFields())
    true

is 函數(shù)驗證 NoFields 的“兩個”實例是否為同一個。有關(guān)單態(tài)類型,后面會詳細講。

有關(guān)復合類型如何實例化,需要 參數(shù)化類型方法這兩個背景知識。將在構(gòu)造函數(shù)中詳細介紹構(gòu)造實例。

不可變復合類型

可以使用關(guān)鍵詞 immutable 替代 type 來定義 不可變 復合類型:

    immutable Complex
      real::Float64
      imag::Float64
    end

這種類型和其他復合類型類似,除了它們的實例不能被更改。不可變復合類型具有以下幾種優(yōu)勢:

  • 它們在一些情況下更高效。像上面 Complex 例子里的類型就被有效地封裝到數(shù)組里,而且有些時候編譯器能夠避免完整地分配不可變對象。
  • 不會與類型的構(gòu)造函數(shù)提供的不變量沖突。
  • 用不可變對象的代碼不容易被侵入。

一個不可變對象可以包含可變對象,比如數(shù)組,域。那些被包含的可變對象仍然保持可變;只有不可變對象自己的域不能變得指向別的對象。

理解不可變復合變量的一個有用的辦法是每個實例都是和特定域的值相關(guān)聯(lián)的 - 這些域的值就能告訴你關(guān)于這個對象的一切。相反地,一個可變的對象就如同一個小的容器可能包含了各種各樣的值,所以它不能從它的域的值確定出這個對象。在決定是否把一個類型定義為不變的時候,先問問是否兩個實例包含相同的域的值就被認為是相同,或者它們會獨立地改變。如果它們被認為是相同的,那么這個類型就該被定義成不可變的。

再次強調(diào)下, Julia 中不可變類型有兩個重要的特性:

  • 不可變復合類型的數(shù)據(jù)在傳遞時會被拷貝 (在賦值時是這樣, 在調(diào)用函數(shù)時也是這樣), 相對的, 可變類型的數(shù)據(jù)是以引用的方式互相傳遞.
  • 不可變復合類型內(nèi)的域不可改變.

對于有著 C/C++ 背景的讀者, 需要仔細想下為什么這兩個特性是息息相關(guān)的。設(shè)想下,如果這兩個特性是分開的,也就是說,如果數(shù)據(jù)在傳遞時是拷貝的, 然而數(shù)據(jù)內(nèi)部的變量可以被改變, 那么將很難界定某段代碼的實際作用。舉個例子,假設(shè) x 是某個函數(shù)的參數(shù), 同時假設(shè)函數(shù)改變了參數(shù)中的一個域:x.isprocessed = true。根據(jù) x 是值傳遞或者引用傳遞, 在調(diào)用完函數(shù)是, 原來 x 的值有可能沒有改變, 也有可能改變. 為了防止出現(xiàn)這種不確定效應, Julia 限定如果參數(shù)是值傳遞, 其內(nèi)部域的值不可改變。

被聲明類型

以上的三種類型是緊密相關(guān)的。它們有相同的特性:

  • 明確地被聲明
  • 有名字
  • 有明確的父類
  • 可以有參數(shù)

正因有共有的特性,這些類型內(nèi)在地表達為同一種概念的實例,DataType,是以下類型之一:

    julia> typeof(Real)
    DataType

    julia> typeof(Int)
    DataType

DataType 既可以抽象也可以具體。如果是具體的,它會擁有既定的大小,存儲安排和(可選的)名域。所以一個位類型是一個大小非零的 DataType,但沒有名域。一個復合類型是一個可能擁有名域也可以為空集(大小為零)的 DataType 。

在這個系統(tǒng)里的每一個具體的值都是某個 DataType 的實例,或者一個多元組。

多元組類型

多元組的類型是類型的多元組:

    julia> typeof((1,"foo",2.5))
    (Int64,ASCIIString,Float64)

類型多元組可以在任何需要類型的地方使用:

    julia> (1,"foo",2.5) :: (Int64,String,Any)
    (1,"foo",2.5)

    julia> (1,"foo",2.5) :: (Int64,String,Float32)
    ERROR: type: typeassert: expected (Int64,String,Float32), got (Int64,ASCIIString,Float64)

如果類型多元組中有非類型出現(xiàn),會報錯:

    julia> (1,"foo",2.5) :: (Int64,String,3)
    ERROR: type: typeassert: expected Type{T<:Top}, got (DataType,DataType,Int64)

注意,空多元組 () 的類型是其本身:

    julia> typeof(())
    ()

多元組類型是關(guān)于它的組成類型是協(xié)變的,一個多元組是另一個多元組的子類型意味著對應的第一個多元組的各元素的類型是第二個多元組對應元素類型的子類型。比如:

    julia> (Int,String) <: (Real,Any)
    true

    julia> (Int,String) <: (Real,Real)
    false

    julia> (Int,String) <: (Real,)
    false

直觀地看,這就像一個函數(shù)的各個參數(shù)的類型必須是函數(shù)簽名的子類型(當簽名匹配的時候)。

類型共用體

類型共用體是特殊的抽象類型,使用 Union 函數(shù)來聲明:

    julia> IntOrString = Union(Int,String)
    Union(String,Int64)

    julia> 1 :: IntOrString
    1

    julia> "Hello!" :: IntOrString
    "Hello!"

    julia> 1.0 :: IntOrString
    ERROR: type: typeassert: expected Union(String,Int64), got Float64

不含任何類型的類型共用體,是“底”類型 None

    julia> Union()
    None

抽象類型 None 是所有其它類型的子類型,且沒有實例。零參的 Union 調(diào)用,將返回無實例的類型 None 。

參數(shù)化類型

Julia 的類型系統(tǒng)支持參數(shù)化:類型可以引入?yún)?shù),這樣類型聲明為每種可能的參數(shù)組合聲明一個新類型。

所有被聲明的類型(DataType 的變體)都可以使用同樣的語法來參數(shù)化。我們將按照如下順序來討論:參數(shù)化符合類型、參數(shù)化抽象類型、參數(shù)化位類型。

參數(shù)化復合類型

    abstract Pointy{T}
    type Point{T} <: Pointy{T}
      x::T
      y::T
    end

類型參數(shù)跟在類型名后,用花括號括起來:

    type Point{T}
      x::T
      y::T
    end

這個聲明定義了新參數(shù)化類型 Point{T} ,它有兩個 T 類型的“坐標軸”。參數(shù)化類型可以是任何類型(也可以是整數(shù),此例中我們用的是類型)。具體類型 Point{Float64} 等價于將 Point 中的 T 替換為 Float64 后的類型。上例實際上聲明了許多種類型:Point{Float64}, Point{String}, Point{Int64} 等等,因此,現(xiàn)在每個都是可以使用的具體類型:

    julia> Point{Float64}
    Point{Float64} (constructor with 1 method)

    julia> Point{String}
    Point{String} (constructor with 1 method)

Point 本身也是個有效的類型對象:

    julia> Point
    Point{T} (constructor with 1 method)

Point 在這兒是一個抽象類型,它包含所有如 Point{Float64}, Point{String} 之類的具體實例:

    julia> Point{Float64} <: Point
    true

    julia> Point{String} <: Point
    true

其它類型則不是其子類型:

    julia> Float64 <: Point
    false

    julia> String <: Point
    false

Point 不同 T 值所聲明的具體類型之間,不能互相作為子類型:

    julia> Point{Float64} <: Point{Int64}
    false

    julia> Point{Float64} <: Point{Real}
    false

這一點非常重要:

雖然 Float64 <: Real, Point{Float64} <: Point{Real} 不成立!

換句話說,Julia 的類型參數(shù)是 不相關(guān) 的。盡管 Point{Float64} 的實例按照概念來說,應該是 Point{Real} 的實例,但兩者在內(nèi)存中的表示上有區(qū)別:

  • Point{Float64} 的實例可以簡便、有效地表示 64 位數(shù)對兒
  • Point{Real} 的實例可以表示任意 Real 實例的數(shù)對兒。由于 Real 的實例可以為任意大小、任意結(jié)構(gòu),因此 Point{Real} 實際上表示指向 Real 對象的指針對兒

上述區(qū)別在數(shù)組中更明顯: Array{Float64} 可以在一塊連續(xù)內(nèi)存中存儲 64 位浮點數(shù),而 Array{Real} 則保存指向每個 Real 對象的指針數(shù)組。而每個 Real 對象的大小,可能比 64 位浮點數(shù)的大。

構(gòu)造函數(shù)中將介紹如何給復合類型自定義構(gòu)造方法,但如果沒有特殊構(gòu)造聲明時,默認有兩種構(gòu)造新復合對象的方法:一種是明確指明構(gòu)造方法的類型參數(shù);另一種是由對象構(gòu)造方法的參數(shù)來隱含類型參數(shù)。

指明構(gòu)造方法的類型參數(shù):

    julia> Point{Float64}(1.0,2.0)
    Point{Float64}(1.0,2.0)

    julia> typeof(ans)
    Point{Float64} (constructor with 1 method)

參數(shù)個數(shù)應與構(gòu)造函數(shù)相匹配:

    julia> Point{Float64}(1.0)
    ERROR: no method Point{Float64}(Float64)

    julia> Point{Float64}(1.0,2.0,3.0)
    ERROR: no method Point{Float64}(Float64, Float64, Float64)

對于帶有類型參數(shù)的類型,因為重載構(gòu)造函數(shù)是不可能的,所以只有一種默認構(gòu)造函數(shù)被自動生成——這個構(gòu)造函數(shù)接受任何參數(shù)并且把們轉(zhuǎn)換成對應的字段類型并賦值

大多數(shù)情況下不需要提供 Point 對象的類型,它可由參數(shù)類型來提供信息。因此,可以不提供 T 的值:

    julia> Point(1.0,2.0)
    Point{Float64}(1.0,2.0)

    julia> typeof(ans)
    Point{Float64} (constructor with 1 method)

    julia> Point(1,2)
    Point{Int64}(1,2)

    julia> typeof(ans)
    Point{Int64} (constructor with 1 method)

上例中,Point 的兩個參數(shù)類型相同,因此 T 可以省略。但當參數(shù)類型不同時,會報錯:

    julia> Point(1,2.5)
    ERROR: `Point{T}` has no method matching Point{T}(::Int64, ::Float64)

這種情況其實也可以處理,詳見構(gòu)造函數(shù)。

參數(shù)化抽象類型

類似地,參數(shù)化抽象類型聲明一個抽象類型的集合:

    abstract Pointy{T}

對每個類型或整數(shù)值 T,Pointy{T} 都是一個不同的抽象類型。Pointy 的每個實例都是它的子類型:

    julia> Pointy{Int64} <: Pointy
    true

    julia> Pointy{1} <: Pointy
    true

參數(shù)化抽象類型也是不相關(guān)的:


    julia> Pointy{Float64} <: Pointy{Real}
    false

    julia> Pointy{Real} <: Pointy{Float64}
    false

可以如下聲明 Point{T}Pointy{T} 的子類型:

    type Point{T} <: Pointy{T}
      x::T
      y::T
    end

對每個 T,都有 Point{T}Pointy{T} 的子類型:

    julia> Point{Float64} <: Pointy{Float64}
    true

    julia> Point{Real} <: Pointy{Real}
    true

    julia> Point{String} <: Pointy{String}
    true

它們?nèi)匀皇遣幌嚓P(guān)的:

    julia> Point{Float64} <: Pointy{Real}
    false

參數(shù)化抽象類型 Pointy 有什么用呢?假設(shè)我們要構(gòu)造一個坐標點的實現(xiàn),點都在對角線 x = y 上,因此我們只需要一個坐標軸:


    type DiagPoint{T} <: Pointy{T}
      x::T
    end

Point{Float64}DiagPoint{Float64} 都是 Pointy{Float64} 抽象類型的實現(xiàn),這對其它可選類型 T 也一樣。 Pointy 可以作為它的子類型的公共接口。有關(guān)方法和重載,詳見下一節(jié) :ref:man-methods

有時需要對 T 的范圍做限制:

    abstract Pointy{T<:Real}

此時, T 只能是 Real 的子類型:

    julia> Pointy{Float64}
    Pointy{Float64}

    julia> Pointy{Real}
    Pointy{Real}

    julia> Pointy{String}
    ERROR: type: Pointy: in T, expected T<:Real, got Type{String}

    julia> Pointy{1}
    ERROR: type: Pointy: in T, expected T<:Real, got Int64

參數(shù)化復合類型的類型參數(shù),也可以同樣被限制:

    type Point{T<:Real} <: Pointy{T}
      x::T
      y::T
    end

下面是 Julia 的 Rational 的 immutable 類型是如何定義的,這個類型表示分數(shù):

    immutable Rational{T<:Integer} <: Real
      num::T
      den::T
    end

單態(tài)類型

單態(tài)類型是一種特殊的抽象參數(shù)化類型。對每個類型 T ,抽象類型“單態(tài)” Type{T} 的實例為對象 T。來看些例子:

    julia> isa(Float64, Type{Float64})
    true

    julia> isa(Real, Type{Float64})
    false

    julia> isa(Real, Type{Real})
    true

    julia> isa(Float64, Type{Real})
    false

換句話說,僅當 AB 是同一個對象,且此對象是類型時,isa(A,Type{B}) 才返回真。沒有參數(shù)時,Type 僅是抽象類型,所有的類型都是它的實例,包括單態(tài)類型:

    julia> isa(Type{Float64},Type)
    true

    julia> isa(Float64,Type)
    true

    julia> isa(Real,Type)
    true

只有對象是類型時,才是 Type 的實例:

    julia> isa(1,Type)
    false

    julia> isa("foo",Type)
    false

Julia 中只有類型對象才有單態(tài)類型。

參數(shù)化位類型

可以參數(shù)化地聲明位類型。例如,Julia 中指針被定義為位類型:

    # 32-bit system:
    bitstype 32 Ptr{T}

    # 64-bit system:
    bitstype 64 Ptr{T}

這兒的參數(shù)類型 T 不是用來做類型定義,而是個抽象標簽,它定義了一組結(jié)構(gòu)相同的類型,這些類型僅能由類型參數(shù)來區(qū)分。盡管 Ptr{Float64}Ptr{Int64} 的表示是一樣的,它們是不同的類型。所有的特定指針類型,都是 Ptr 類型的子類型:

    julia> Ptr{Float64} <: Ptr
    true

    julia> Ptr{Int64} <: Ptr
    true

類型別名

Julia 提供 typealias 機制來實現(xiàn)類型別名。如,UintUint32Uint64 的類型別名,這取決于系統(tǒng)的指針大?。?

    # 32-bit system:
    julia> Uint
    Uint32

    # 64-bit system:
    julia> Uint
    Uint64

它是通過 base/boot.jl 中的代碼實現(xiàn)的:

    if is(Int,Int64)
        typealias Uint Uint64
    else
        typealias Uint Uint32
    end

對參數(shù)化類型,typealias 提供了簡單的參數(shù)化類型名。Julia 的數(shù)組類型為 Array{T,n} ,其中 T 是元素類型, n 是數(shù)組維度的數(shù)值。為簡單起見,Array{Float64} 可以只指明元素類型而不需指明維度:

    julia> Array{Float64,1} <: Array{Float64} <: Array
    true

``Vector`` 和 ``Matrix`` 對象是如下定義的:

    typealias Vector{T} Array{T,1}
    typealias Matrix{T} Array{T,2}

類型運算

Julia 中,類型本身也是對象,可以對其使用普通的函數(shù)。如 <: 運算符,可以判斷左側(cè)是否是右側(cè)的子類型。

isa 函數(shù)檢測對象是否屬于某個指定的類型:

    julia> isa(1,Int)
    true

    julia> isa(1,FloatingPoint)
    false

typeof 函數(shù)返回參數(shù)的類型。類型也是對象,因此它也有類型:

    julia> typeof(Rational)
    DataType

    julia> typeof(Union(Real,Float64,Rational))
    DataType

    julia> typeof((Rational,None))
    (DataType,UnionType)

類型的類型是什么?它們的類型是 DataType

    julia> typeof(DataType)
    DataType

    julia> typeof(UnionType)
    DataType

讀者也許會注意到,DataType 類似于空多元組(詳見上文 )。因此,遞歸使用 ()DataType 所組成的多元組的類型,是該類型本身:

    julia> typeof(())
    ()

    julia> typeof(DataType)
    DataType

    julia> typeof(((),))
    ((),)

    julia> typeof((DataType,))
    (DataType,)

    julia> typeof(((),DataType))
    ((),DataType)

super 可以指明一些類型的父類型。只有聲明的類型(DataType)才有父類型:

    julia> super(Float64)
    FloatingPoint

    julia> super(Number)
    Any

    julia> super(String)
    Any

    julia> super(Any)
    Any

對其它類型對象(或非類型對象)使用 super ,會引發(fā) “no method” 錯誤:

    julia> super(Union(Float64,Int64))
    ERROR: `super` has no method matching super(::Type{Union(Float64,Int64)})

    julia> super(None)
    ERROR: `super` has no method matching super(::Type{None})

    julia> super((Float64,Int64))
    ERROR: `super` has no method matching super(::Type{(Float64,Int64)})
上一篇:模塊下一篇:運行外部程序