Julia編程基礎(三):一文掌握Julia的變量與常量

本文是《Julia 編程基礎》開源版本第3章:變量與常量。本書旨在幫助編程愛好者和專業程序員快速地熟悉 Julia 編程語言,並能夠在夯實基礎的前提下寫出優雅、高效的程序。這一系列文章由 郝林 採用 CC BY-NC-ND 4.0知識共享 署名-非商業性使用-禁止演繹 4.0 國際 許可協議)進行許可,請在轉載之前仔細閱讀上述許可協議。

本書的示例項目名爲Programs.jl,地址在這裏。其中會包含本書所講的大部分代碼,但並不是那些代碼的完全拷貝。這個示例項目中的代碼旨在幫助本書讀者更好地記憶和理解書中的要點。它們算是對書中代碼的再整理和補充。

Julia 是一種可選類型化的編程語言。Julia 代碼中的任何值都是有類型的。而一個區別在於,一個值的類型是由我們顯式指定的,還是由 Julia 在自行推斷之後附加上的。例如:

julia> typeof(2020)
Int64

julia> 

我調用了一個名爲typeof的函數,並把2020作爲參數值傳給了它。2020本身是一個代表了整數值的字面量(literal)。雖然我沒有明確指定這個值是什麼類型的,但是 Julia 卻可以推斷出來。經過推斷,Julia 認爲它的類型是Int64——一個寬度爲 64 個比特(bit)的有符號的整數類型。Int64本身是一個代表了類型的標識符,也可以稱之爲類型字面量。在一個 64 位的計算機系統當中,Julia 程序中的整數值的默認類型就是Int64。如果你使用的是 32 位的計算機系統,那麼這裏回顯的內容就應該是Int32

我們在做運算的時候,不太可能只使用值本身去參與運算。因爲總有一些中間結果需要被保存下來。就算我們使用計算器去做一些稍微複雜一點的算術運算,肯定也是如此。對於計算機系統而言,那些中間結果可以被暫存到某個內存地址上。當需要它的時候,我們再去這個地址上去取。

內存地址記憶起來會比較困難。所以,一個更好的方式是,使用一個代號(或者說標識符)去代表某個中間結果。或者說,把一個標識符與一個值綁定在一起,當我們輸入這個標識符的時候就相當於輸入了這個值。這種可變的綁定關係就被稱爲變量。這個標識符就被稱爲變量名。

3.1 變量的定義

變量不只能代表所謂的中間結果,而是可以代表任何值。當我們在 REPL 環境中定義一個變量的時候,它就會回顯該變量名所代表的值。例如:

julia> x = 2020
2020

julia> 

在這之後,我們也可以輸入這個變量名,以此讓 REPL 環境回顯它代表的那個值:

julia> x
2020

julia> 

然而,當我們輸入y這個標識符的時候,會發現它無法回顯某個值:

julia> y
ERROR: UndefVarError: y not defined

julia> 

這是因爲y還沒有被定義,Julia 並不知道它代表了什麼。那什麼是定義呢?更確切地說,什麼是變量的定義呢?我們在前面說過,變量相當於一個標識符與值的綁定。那麼,對這種綁定的描述就是變量的定義。在 Julia 中,變量的定義一般由標識符、賦值符號=和值字面量構成。就像我們在前面展示的那樣。

3.2 變量的命名

3.2.1 一般規則

Julia 變量的名稱是大小寫敏感的。也就是說,yY並不是同一個標識符,它們可以代表不同的值。

變量名必須以大寫的英文字母A-Z、小寫的英文字母a-z、下劃線_,或者代碼點大於00A0的 Unicode 字符開頭。代表數字的字符不能作爲變量名的首字符,但是可以被包含在名稱的後續部分中。當然,變量名中肯定不能夾雜空格符,以及像製表符、換行符這樣的不可打印字符。

總之,大部分 Unicode 字符都可以作爲變量名的一部分。即使你不知道什麼是 Unicode 編碼標準也沒有關係。我們會在後面討論字符和字符串的時候介紹它。

由此,Julia 允許我們把數學符合當做變量名,例如:

julia> δ = 3
3

julia> 

你可能會問:怎麼才能輸入δ?這又涉及到了 LaTeX 符號。簡單來說,LaTeX 是一個排版系統,常被用來排版學術論文。因爲這種論文中經常會出現複雜表格和數學公式,所以 LaTeX 自有一套方法去表現它們。我們沒必要現在就去專門學習 LaTeX。你只要知道,如果需要輸入數學符號的話,那麼就可以利用 LaTeX 符號。

具體的做法是,先輸入某個 LaTeX 符號(比如\delta)再敲擊 Tab 鍵,隨後對應的數學符號(比如δ)就可以顯示出來了。如果你不知道一個數學符號對應的 LaTeX 符號是什麼,那麼可以在 REPL 環境的 help 模式下把那個數學符號複製、黏貼到提示符的後面,然後回車。比如這樣:

help?> δ
"δ" can be typed by \delta<tab>

search: δ

  No documentation found.

  δ is of type Int64.

  Summary
  ≡≡≡≡≡≡≡≡≡

  primitive type Int64 <: Signed

  Supertype Hierarchy
  ≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡

  Int64 <: Signed <: Integer <: Real <: Number <: Any

julia> 

3.2.2 變量名與關鍵字

雖然變量命名的自由度很大,但還是有一些約束的。其中最重要的是,你不能使用 Julia 已有的單一的關鍵字作爲變量名。更廣泛地說,所有程序定義的名稱都不能與任何一個單一的關鍵字等同。Julia 中單一的關鍵字目前一共有 29 個。我把它們分成了 7 個類別:

  • 表示值的關鍵字:falsetrue
  • 定義程序定義的關鍵字:constgloballocalfunctionmacrostruct
  • 定義(無名)代碼塊的關鍵字:begindoendletquote
  • 定義模塊的關鍵字:baremodulemodule
  • 引入或導出的關鍵字:importusingexport
  • 控制流程的關鍵字:breakcontinueelseelseifforifreturnwhile
  • 處理錯誤的關鍵字:catchfinallytry

其中,程序定義指的是變量、常量、類型、有名函數、宏或者結構體。所有的程序定義都是有名稱的,或者說可以由某個標識符指代。其中的有名函數和宏也可以被稱爲有名的代碼塊。

所謂的無名代碼塊,與有名的代碼塊一樣也是有明顯邊界的一段代碼,但是並沒有一個標識符可以指代它們。注意,我把關鍵字end劃分爲了定義(無名)代碼塊的關鍵字。但實際上,我們在定義有名函數、宏、結構體和模塊的時候也需要用到它。

另外,模塊也是一個有名的代碼塊。並且,一個 Julia 程序的主模塊(即入口程序所屬的那個模塊)就是它的最外層代碼塊。在 Julia 中,並沒有一個可以囊括所有代碼的全局代碼塊。這與很多主流的編程語言都是不同的。我們可以說,Julia 程序就是由一些具有依賴關係的模塊組成的。換句話講,Julia 程序中的代碼要麼在主模塊中,要麼在主模塊依賴的那些模塊中。我會在後面專門用一章來講解模塊。

關於以上這些關鍵字的用法,我們在後面也都會講到。所以你現在只要知道它們不能被作爲變量名就可以了。

3.2.3 變量名與作用域

我們在前面說過,Int64是一個代表了類型的標識符。又因爲這個標識符的作用域相當於是全局的,所以我們設定的變量名就不能與它重複。更寬泛地講,我們的變量名肯定不能與任何一個 Julia 預定義的類型的名稱相同。

什麼叫作用域呢?其含義是,標識符可以被其他代碼直接引用的一個區域。一旦超出這個區域,這個標識符在默認情況下就是不可見的。比如,我們在第 1 章定義過一個叫做MyArgs的模塊,並且其中有一個名叫get_parameter的函數。當時的情況是,我們無法在這個模塊之外直接使用這個函數的本名來引用它。如果你翻回去看的話,就能見到我們的引用方式是MyArgs.get_parameter。這被稱爲(針對這個get_parameter函數的)限定名。

嚴格來講,Julia 中沒有任何一個標識符的作用域真正是全局的。但是,由於我們定義的所有模塊都隱含了Core模塊,所以在該模塊中直接定義的那些標識符的作用域就相當於是全局的。Int64以及其他代表了某個類型的標識符都在其中。

因此,我們設定的變量名肯定不能與Core模塊中那些基本的程序定義重名。

關於作用域,還有一些內容是我們必須要知道的。Julia 中的很多代碼塊都會自成一個作用域,比如模塊就是這樣。但由於這會涉及到一些我們還未曾講到的重要知識,所以我把它們放到了流程控制的那一章。那裏會有關於變量作用域的更多內容。

3.3 變量的類型

我們都知道,一個變量的值是可變的。但你可能不知道的是,在 Julia 中,變量的類型也是可以改變的。更確切地說,我們可以爲同一個變量先後賦予不同類型的值。Julia 的變量實際上是沒有類型的,只有值纔有類型。但爲了描述方便,我們仍然會說“變量的類型”。你要記住,它真正的意思是“變量中的值的類型”。下面舉一個例子:

julia> y = 2020
2050

julia> y = "2050"
"2050"

julia> 

雖然我們還沒有專門講類型,但在這裏可以先形成一個簡單的認知。在上例中,我先把一個Int64類型的值2020賦給了變量y。緊接着,我又把一個String類型(也就是字符串類型)的值"2050"賦給了這個變量。注意,字符串類型的值一般都是由一對雙引號包裹的。

顯然,在第二次賦值之前和之後,變量y的類型是不同的。雖然 Julia 允許我們隨意改變一個變量的類型,但是這樣做往往會對程序的性能造成不小的負面影響。所以官方在大多數情況下還是不推薦這種做法的。我們可以利用語法規則來約束對變量類型的隨意變更,或者說約束賦予變量的那些值的類型。更具體地講,我們可以在編程的時候用附加類型標識符的方式讓變量的類型固定下來,比如:y::Int64

操作符::可以將類型標識符附加到程序中的變量和表達式之後。下面是它的兩個重要用途:

  1. 它可以用於類型標註,爲編譯器提供額外的類型信息,從而在某些情況下提高程序的性能。
  2. 它可以用於類型斷言,判斷某個值或者某個表達式的結果是否是某個類型的。

3.3.1 類型標註

當用於類型標註時,操作符::及其右側的類型標識符就意味着這個變量將永遠是某個類型的。我們賦予這個變量的每一個值都將被自動地轉換爲定義該變量時所聲明的那個類型的值。例如,我們有這樣一個函數:

function get_uint32(x)
    y::UInt32 = x
    y
end

我先來簡單地解釋一下:函數的定義一般以關鍵字function開頭,並以關鍵字end結尾,後者獨佔一行。在function右側的是函數的名稱,這兩者之間需要用一個空格分隔。這裏的函數名稱是get_uint32。而緊挨在函數名稱右側的是由圓括號包裹的函數參數,這裏唯一的函數參數是x

被夾在首行和尾行之間的是函數體,可以由若干個表達式組成。並且,如果沒有顯式指定,那麼最後一個表達式的求值結果就將是這個函數的結果。在這裏,y的值就是函數get_uint32的結果。這個函數所做的事情就是,把由參數x代表的那個值賦給了局部變量y,然後把y的值作爲函數結果返回。

所謂的局部變量是指,沒有直接定義在模塊中而是定義在了模塊包含的某個代碼塊中的那些變量。在上例中,我們在get_uint32函數中定義的參數x和變量y都屬於局部變量。相對應的,全局變量就是直接定義在模塊中的那些變量。更寬泛地講,直接定義在模塊中的變量、常量、類型、有名函數、宏和結構體可以被統稱爲全局程序定義。注意,這裏的“全局”是針對模塊而言的,而不是針對所有的代碼。

言歸正傳。我們沒有對參數x附加類型標註,所以原則上x代表的可以是任何一個類型的值。但我們把變量y的類型聲明爲了UInt32。也就是說,該變量的值必須是UInt32類型的。UInt32類型是一個寬度爲 32 個比特(bit)的無符號的整數類型。如此一來,當我們把x的值賦給y時,就有可能引起自動的類型轉換。例如:

julia> get_uint32(2020)
0x000007e4

julia> typeof(get_uint32(2020))
UInt32

julia> 

我們已經知道,整數值2020在默認情況下的類型是Int64。因此,我在調用get_uint32函數的時候把2020作爲參數值傳入,就一定會引起相應的類型轉換。這次調用得到的結果值是0x000007e4,是一個用十六進制表示的整數值。在 Julia 中,無符號的整數值一般都是這樣表示的。如果我們再把0x000007e4轉換爲有符號整數值的話,就會是原先的2020

julia> Int32(0x000007e4)
2020

julia> 

每一個整數類型都是有一個表示範圍的。或者說,一個整數類型的值只能表示在一定範圍之內的整數。比如,UInt32類型的值就無法表示負數。因此,如果我們把-2020傳入get_uint32函數,就會引發一個錯誤:

julia> get_uint32(-2020)
ERROR: InexactError: trunc(UInt32, -2020)
Stacktrace:
 [1] throw_inexacterror(::Symbol, ::Any, ::Int64) at ./boot.jl:583
 [2] checked_trunc_uint at ./boot.jl:613 [inlined]
 [3] toUInt32 at ./boot.jl:697 [inlined]
 [4] Type at ./boot.jl:737 [inlined]
 [5] convert at ./number.jl:7 [inlined]
 [6] get_uint32(::Int64) at ./REPL[36]:2
 [7] top-level scope at none:0

julia> 

從回顯首行的錯誤信息可知,Julia 拋出了一個InexactError類型的錯誤。出現這類錯誤就意味着 Julia 無法把源值(這裏是-2020)轉換成目的類型(這裏是UInt32)的值。另外,trunc是一個函數的名稱。Julia 此次正是使用這個函數進行類型轉換的。

當我們傳入一個浮點數值、字符串值或者其他的UInt32類型無法表示的值的時候,情況也會是類似的。只不過錯誤的類型和具體信息可能會有所不同。

到了這裏,你可能會疑惑:爲什麼我們講變量的類型標註還需要定義一個函數呢?直接在 REPL 環境中演示不就好了嗎?這實際上涉及到 Julia 語言的一個小缺陷。

在 Julia 程序中,我們無法爲全局變量添加類型標註。

還記得嗎?所謂的全局變量就是直接定義在模塊中的那些變量。我們編寫的任何 Julia 代碼都會屬於某個模塊。即使我們沒有顯式地把它們包含在某個模塊中,也會是如此。更具體地講,我們在 REPL 環境中輸入的代碼默認都屬於Main模塊。這與我們直接在源碼文件中寫入 Julia 代碼是一樣的。正因爲如此,我們才能在這樣的環境中僅通過名稱就可以引用到之前寫入的程序定義。

由此可知,我們在 REPL 環境中直接定義附帶類型標註的變量是行不通的,就像這樣:

julia> x::UInt32 = 2020
ERROR: syntax: type declarations on global variables are not yet supported

julia> 

一個可以繞開這個缺陷的方法是,使用Ref{T}類型的常量作爲替代。“Ref”是 Reference 的縮寫,可以被翻譯爲“引用”。Ref{T}類型本身是一個參數化的類型,其中的那對花括號就是標誌。而花括號中的T表示的就是類型參數(type parameter),它在這裏指代被引用的值的類型。我們可以在實際應用中自行設定這個類型。示例如下:

julia> const xref = Ref{UInt32}(2020)
Base.RefValue{UInt32}(0x000007e4)

julia> 

我使用關鍵字const定義了一個名爲xref的常量,並把一個Ref{UInt32}類型的值賦給了它。由這個類型的字面量可知,我規定xref引用的值必須是UInt32類型的。另外,在最右側的圓括號中的2020就是xref初始引用的值。也就是說,xref的值中又引用了另外一個值,而後者纔是我們真正需要的。

由於xref是一個常量,所以如果我們試圖改變它的類型,就會引發一個錯誤。不過,我們仍然可以改變xref引用的值,比如:xref[] = 2050。這裏的操作符[]就是用來讀出或寫入Ref{T}類型值所引用的值的。如此一來,我們就相當於擁有了一個具有固定類型的全局變量。關於常量的更多知識,我們到後面就會講到。

不過無論怎樣,這終歸只是繞開缺陷,而不是修補缺陷。Julia 語言的官方團隊已經在計劃對此進行修補了。預計在之後的某個 1.x 版本,我們就可以直接定義帶有類型標註的全局變量了。

3.3.2 類型斷言

當用於類型斷言時,操作符::可以被解讀爲“A 是否爲 B 的一個實例”。其中 A 代表該操作符左側的值,而 B 則代表操作符右側的類型。例如:

julia> "abc"::String
"abc"

julia> "abc"::Char
ERROR: TypeError: in typeassert, expected Char, got String
Stacktrace:
 [1] top-level scope at none:0

julia> 

我先利用操作符::判斷值"abc"是否爲String類型的一個實例,並得到回顯"abc"。這就說明該類型斷言成功了(或者說通過了)。注意,在這種情況下,若有必要 Julia 會對::左側的值進行類型轉換,把它轉換爲處於::右側的那個類型的值。這是通過調用convert函數實現的。

之後,我又判斷"abc"是否爲Char類型的一個實例,並使得 Julia 報錯。所以此類型斷言失敗(或者說未通過)。只用眼睛觀察,我們就可以知道"abc"是一個字符串類型的值。而且,它並不是一個單一的字符。字符類型的值只能代表一個字符,並且需要由一對單引號包裹。

注意,像StringChar這樣的類型都屬於具體類型。Julia 中還有一種類型叫做抽象類型。它們的名稱很多都有着明顯且一致的前綴,比如:AbstractStringAbstractChar。在進行類型斷言的時候,如果右側的類型是一個具體類型,那麼只有左側的值是該類型的一個實例,斷言纔會成功。而如果右側的類型是一個抽象類型,那麼只要左側的值是這個抽象類型的任意一個子類型的實例就可以使斷言成功。又由於 Julia 中的抽象類型都是不能被實例化的,因此這個子類型也必然是一個具體類型。下面看一個例子:

julia> "abc"::AbstractString
"abc"

julia> "abc"::AbstractChar
ERROR: TypeError: in typeassert, expected AbstractChar, got String
Stacktrace:
 [1] top-level scope at none:0

julia> 

因爲StringAbstractString的子類型,所以第一個類型斷言成功。但是,由於String並不是AbstractChar的子類型,因此第二個類型斷言失敗。

我們幾乎可以把類型斷言用在任何地方,只要其左側的是一個值或是一個表達式就可以。但要注意,一旦斷言失敗,錯誤就會被拋出來。程序會因此中斷,除非我們合理地處理了錯誤。如果我們對於某個類型斷言非常沒有把握,而且不想在斷言失敗時得到一個錯誤,那麼可以使用isa函數作爲替代。例如:

julia> isa("abc", AbstractChar)
false

julia> 

不過要注意,我們調用isa函數之後只能得到truefalse的結果。

3.4 常量

在 Julia 中,常量是一種特殊的變量。我們可以使用關鍵字const來定義一個常量:

const A = 2020

當需要同時定義多個常量時,我們還可以使用平行賦值法:

const W, U, V = 2020, 2030, 2050

在這裏,常量WUV的值分別爲202020302050

我們已經知道,爲全局變量附加類型標註目前是行不通的。實際上,Julia 官方現在不建議我們在程序中使用全局變量。因爲全局變量總是會給程序帶來不小的性能負擔。這正是用於全局變量的值及其類型都是可以被隨時改變的。而全局常量可以讓這個問題迎刃而解。所以,我們應該使用全局常量,而不是全局變量。這也是 Julia 中很重要的一條編碼建議。

相反,在局部,我們應該使用局部變量,而不是局部常量。因爲定義一個局部常量完全是沒有必要的。Julia 一旦在局部碰到一個不變的變量就會把它優化成常量。你其實用不着專門去記這條編碼建議。因爲定義局部常量根本就不符合 Julia 的語法規則,例如:

julia> function get_uint32(x)
           const y::UInt32 = x
           y
       end
ERROR: syntax: unsupported `const` declaration on local variable around REPL[1]:2

julia> 

不過,這個語法規則的制定原因我們還是應該瞭解的。

另外,與其他的一些編程語言不同,Julia 中的常量的值不僅可以是數值和字符串,還可以是像數組這樣的可變對象。也正因爲如此,Julia 常量只能保證名稱與值之間的綁定是不可變的,但是並不能防止值本身的變化,比如數組中的某個元素值的改變。所以,我們儘量不要把本身可變的值賦給全局常量。

下面,我們來說 Julia 常量的最重要的 3 個特性。其中的一個比較反直覺的特性是:我們似乎可以改變一個常量的值。更明確地說,我們對常量的重新賦值只會引發一個警告,而不會得到一個錯誤。例如,我們看似可以對前面定義過的常量A進行重新賦值:

julia> A = 2050
WARNING: redefining constant A
2050

julia> 

根據警告的內容可知,Julia 稱其爲對常量的重新定義。這相當於放棄了以前的常量定義,而採用了新的定義。那麼,常量的重新定義與我們之前說的重新賦值到底有什麼不一樣呢?我們可以通過下面的示例進行理解。

julia> const C = 2020 
2020

julia> f() = C + 30
f (generic function with 1 method)

julia> f()
2050

我先定義了一個名稱爲C、值爲2020的常量,緊接着又用一種簡易的方式定義了一個名稱爲f的函數。這個函數的功能很簡單,即:在常量C代表的值之上再加30並將結果返回。現在,我們重新定義常量C

julia> C = 2030
WARNING: redefining constant C
2030

然後,再次調用函數f

julia> f()
2050

julia> 

可以看到,調用f函數後得到的結果依然爲2050。這是因爲函數f使用的仍然是在它之前定義的那個常量C,而不是我們重新定義的常量C。我們可以想象,如果真有一種方法可以對常量C進行重新賦值的話,那麼再次調用f函數肯定不會得到這樣的結果。

因此,在 Julia 中,我們只能對常量進行重新定義,而不能進行重新賦值。正因爲常量的重新定義所帶來的效果有些反直覺,所以我們最好還是不要重新定義常量。爲此,我們還應該讓常量的名稱看起來特別一些,比如全大寫,以避免之後的誤操作。我們還要注意程序輸出中的此類警告,並及時糾正這種不好的做法。

Julia 常量的第二個重要特性是,如果我們在重新定義常量的時候試圖賦予它一個不同類型的值,那麼就會得到一個錯誤。例如:

julia> C = "2020"
ERROR: invalid redefinition of constant C
Stacktrace:
 [1] top-level scope at none:0

julia> 

注意,這裏報出的錯誤是“對常量C的重新定義無效”,而不是“不能改變常量C的類型”。所以,這裏的規則是,在對常量進行重新定義時只能賦予一個與前值類型相同的值。

基於此,常量的第三個重要特性就比較好理解了。這個特性就是,如果在重新定義常量時賦予它相同的值,那麼既不會引發警告也不會導致錯誤報告。比如:

julia> const D = "2020"
"2020"

julia> D = "2020"
"2020"

julia> d = "2020"
"2020"

julia> D = d
"2020"

julia> 

不過,需要注意,這只是針對不可變對象(或者說本身不可變的值)而言的。對於可變對象(比如數組),即使前後兩個值看起來相同,Julia 也照樣會發出警告。例如:

julia> const E = ["2020"]
1-element Array{String,1}:
 "2020"

julia> E = ["2020"]
WARNING: redefining constant E
1-element Array{String,1}:
 "2020"

julia> 

所以,還是那句話,我們儘量不要把本身可變的值賦給常量。

由以上特性可知,常量看似可以被當做類型固定的全局變量來使用。但實際上,對常量的重新定義會埋下隱患,而且由此引發的程序錯誤將會很難排查和定位。所以,我們可以使用常量來存儲全局性的對象,但最好不要對它進行重新定義。另外,我們儘量不要把可變對象賦給常量。

3.5 小結

我們在這一章主要講的是變量。我們首先從可以與變量綁定在一起的對象——值——講起。在 Julia 中,任何值都是有類型的。我們在定義一個變量的時候,可以爲它添加標註類型(涉及到操作符::),也可以讓 Julia 自行推斷其類型。我們推薦前者的做法,因爲那樣做會對程序的性能有好處。不過要注意,我們是無法爲全局變量添加類型標註的。

代表變量的標識符、賦值符號=和代表值的字面量共同組成了變量的定義。它把一個值與一個標識符(或稱變量名)綁定在了一起。此後,這個標識符就是那個值的代表。

Julia 對變量名有所限制,但是這種限制還是很寬鬆的。大部分 Unicode 字符都可以被包含在內。不過,變量名不能與 Julia 中任何一個單一的(或者說單詞的)關鍵字重複,也不能與處在同一個作用域中的其他程序定義的名稱重複。

一旦理解了變量,常量的概念就很好理解了。因爲 Julia 的常量就是一種特殊的變量。只不過,常量只能被定義在全局,而不能被定義在局部。另外,我們需要特別注意對常量的重新定義。

除了上述知識,我們還在本章順便說明了程序定義、代碼塊、作用域等概念的含義。你最好記住它們,因爲我們在後面還會有所提及。

值、變量以及類型是 Julia 中最基礎的概念。沒有了它們,我們就無法編寫 Julia 程序。彆着急,我們馬上就會講到第三個基礎概念——類型。

原文鏈接:

https://github.com/hyper0x/JuliaBasics/blob/master/book/ch03.md

系列文章:

Julia編程基礎(一):初識Julia,除了性能堪比C語言還有哪些特性?

Julia編程基礎(二):開發Julia項目必須掌握的預備知識

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章