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

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

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

2.1 REPL 環境及其用法

命令julia爲我們提供了一個簡易但足夠強大的編程環境。這就是 REPL 環境。不過
,REPL 環境並不是 Julia 語言獨有的。像 Python、Ruby 這類現代的動態編程語言大都具備 REPL 環境。

Julia 的 REPL 環境非常有用,尤其是在我們進行試驗性編程的時候。我們可以在其中試着執行一些代碼片段,並在確認無誤之後把這些片段在源碼文件中組裝起來,形成真正的程序。因此,REPL 環境絕對算得上一個優秀的編程學習助手。我起初就是藉助這個環境來學習 Julia 編程的。

2.1.1 初探 REPL

我們已經知道,直接在命令行中輸入julia並回車就可以進入 Julia 的 REPL 環境。下面我們就來說說在進入這個環境之後都能做些什麼。

你還記得我們在上一章使用過的命令julia -e 'a = 5 * 8; println(a)'嗎?現在,我們就在 REPL 環境中輸入其中單引號裏的表達式列表,像這樣:

julia> a = 5 * 8; println(a)
40

julia>

可以看到,REPL 環境在對這兩個表達式進行逐一求值之後就返回了。注意,如果對我們輸入的最後一個表達式進行求值後可以得到顯式的結果,那麼這個結果也會被回顯出來。這與通過前面的命令對表達式進行求值的效果是相同的。不過,它並不會返回到命令行,而是保留在當前的環境下。順便說一句,julia>是 Julia 的 REPL 環境下的提示符。

我們還可以對這兩個表達式分別求值,如:

julia> a = 5 * 8
40

julia> println(a)
40

julia> 

當我們輸入a = 5 * 8並回車之後,REPL 環境會對它進行求值,並在完成後回顯結果。如果你不想讓它立即回顯結果,那麼可以在表達式的最後輸入;,就像這樣:

julia> a = 5 * 8;

julia> println(a);
40

julia> 

注意,40並不是表達式println(a)‌的結果。所以我們在它後面添加;並不會影響到下面的回顯內容。

另外,之所以println(a)‌這個表達式是合法的,是因爲a在當下是一個已定義的變量。REPL 環境會暫存我們給予的所有表達式及其求值結果。所以,我們可以像寫腳本程序那樣在 REPL 環境裏編程。

在 REPL 環境中,如果我們想再看一下上一個表達式的求值結果,那麼僅需要輸入ans並回車,如:

julia> a = 5 * 8;

julia> ans
40

julia> 

我們在 REPL 環境中按下“向上箭頭”鍵可以翻找曾經輸入過的代碼。這時,“向下箭頭”鍵也是有用的,用於向更近時間的方向翻找。當然了,這樣翻找的效率並不高,尤其是在你翻找很久以前的代碼的時候。

如果你想在較大的時間範圍內查找,我建議你去查閱一個名叫repl_history.jl的文件。它被保存在了 Julia 的日誌目錄下。比如,在 macOS 操作系統中,它的存放路徑就是~/.julia/logs/repl_history.jl

2.1.2 主要的 4 種模式

Julia 的 REPL 環境主要有 4 種可供切換的模式。當我們輸入julia命令並進入到 REPL 環境時,它會處於 julia 模式。在這種模式下,我們可以輸入 Julia 語言的任何表達式,並讓它幫我們計算結果。就像我們在前面做的那樣。

我們在 julia 模式中緊挨着提示符輸入],就會進入到 pkg 模式。此模式是用來管理程序包的。比如,在該模式下輸入add <程序包的名稱>就可以安裝某個新的程序包。又比如,輸入update <程序包的名稱>就可以更新某個已安裝的程序包。還比如,僅輸入up並回車就可以更新所有已安裝的程序包。示例如下:

(v1.1) pkg> add DataFrames
 Resolving package versions...
 Installed DiffEqDiffTools ─ v0.12.0
 Installed DataValues ────── v0.4.8
  Updating `~/.julia/environments/v1.1/Project.toml`
  [a93c6f00] + DataFrames v0.18.3
  Updating `~/.julia/environments/v1.1/Manifest.toml`
  [e7dc6d0d] ↑ DataValues v0.4.7 ⇒ v0.4.8
  [01453d9d] ↑ DiffEqDiffTools v0.11.0 ⇒ v0.12.0

(v1.1) pkg> 

注意,在 pkg 模式下,提示符會變爲(v1.1) pkg>。其中的v1.1代表的是 Julia 語言的特性版本。

關於 pkg 模式支持的更多命令,你可以通過在該模式下輸入?或者help進行查詢。另外,如果你想回到 julia 模式,那麼可以同時按下Ctrlc

Julia 的 REPL 環境還支持 shell 模式。我們在 julia 模式中緊挨着提示符輸入英文分號;,就會進入到 shell 模式。這種模式讓我們可以執行普通的 Shell 命令。當我們需要時不時地操縱文件系統時,這樣會很方便,省去了我們在多個命令行之間切換的工作量。與 pkg 模式不同的是,在執行完一個 shell 命令之後,REPL 環境會自動地退出 shell 模式並切換回 julia 模式。

REPL 環境支持的第 4 種主要模式是 help 模式,或者說幫助模式。我們在 julia 模式中緊挨着提示符輸入英文問號?,就會進入到 help 模式。顧名思義,這種模式是用來查詢 Julia 語言的幫助文檔的。在該模式下,我們只要輸入要查詢的類型、變量、結構體、函數、宏等的名稱並回車,REPL 環境就可以搜索並顯示關於它的詳細文檔。隨着搜索結果的顯示,它會自動地切換回 julia 模式。

記住,我們在除了 julia 模式的另外 3 種模式下都可以進行手動地退出。手動退出的方式都是緊挨着提示符按下Backspace鍵或者同時按下Ctrlc

2.1.3 快捷鍵

除了Ctrl+c之外,Julia 的 REPL 環境還支持不少的快捷鍵。最常用的有:

  • Alt+←:將光標移動到左邊最近的單詞開始處。
  • Alt+→:將光標移動到右邊最近的單詞末尾處之後。
  • Ctrl+d:退出julia命令,回到原始的命令行。
  • Ctrl+e:將光標移動到當前行的末尾處之後。
  • Ctrl+h:將光標移動到當前行的開始處。
  • Ctrl+l:清除當前界面中的歷史命令,或稱清屏。
  • Ctrl+r:向後搜索歷史命令。
  • Ctrl+s:向前搜索歷史命令。

關於更多的快捷鍵,你可以查閱 Julia 語言的官方文檔

在這裏,我重點說一下用於搜索歷史命令的快捷鍵,即:Ctrl+sCtrl+r。當我們分別按下這兩個快捷鍵之後,REPL 環境的提示符都會有所變化。當按下Ctrl+s時,提示符的前綴會變爲(forward-i-search);當按下Ctrl+r時,提示符的前綴會變爲(reverse-i-search)

這兩個快捷鍵都可以讓 REPL 環境進入到搜索模式。我在前面說過,我們在 REPL 環境中輸入過的 Julia 表達式或者命令都會被保存在一個名爲repl_history.jl的文件中。搜索模式實際上就是針對這個歷史文件的。

很顯然,這兩個快鍵鍵分別用於從兩個不同的方向在這個歷史文件中搜索指定的內容。只要我們在這種模式下輸入一些字符,它就可以實時地爲我們查找相關的歷史表達式或命令。此時,光標會自動地定位在匹配內容的開始處。並且,當我們再次按下Ctrl+sCtrl+r時,它還會立即爲我們顯示下一個或上一個匹配的內容。

一旦找到想要的表達式或命令,我們就可以直接按下回車鍵。這樣就可以讓 REPL 環境在切換到對應模式的同時把相應的表達式或命令粘貼過來。

舉個例子。我們在 julia 模式中按下Ctrl+r,進入到搜索模式,並隨即輸入add。此時, REPL 環境的界面可能會是這樣:

(reverse-i-search)`add': add DataFrames

在反引號和單引號之間的就是我們剛纔輸入的內容,而在冒號後面的就是 REPL 環境爲我們回顯的第一個搜索結果。由於我們先前在 pkg 模式下安裝過DataFrames程序包,所以這裏的搜索結果是add DataFrames

假設我們要尋找的就是這個命令,那麼可以直接按下回車鍵。此時,上面那一行內容就會變成:

(v1.1) pkg> add DataFrames

REPL 環境知道對應的表達式或命令是在哪個模式下輸入的。這其實並不稀奇,歷史文件中就保存了此類信息。

2.1.4 代碼補全

我們在編程時,尤其是還不那麼熟練的時候,通常記不住那麼多可用的常量、函數、類型等等。不過不用擔心,Julia 語言及其標準庫(即官方提供的程序包的集合)的文檔非常完善。這些文檔可以從各個方面幫助我們用對、用好 Julia 語言。

在 REPL 環境中,我們除了可以很方便地查閱文檔,還可以利用它的代碼補全功能幫助我們選擇要使用的程序定義(具體到這個例子中,就是函數定義),就像這樣:

julia> read[Tab]
read          readavailable  readchomp      readline       readlink
read!         readbytes!     readdir        readlines      readuntil
julia> read

這裏的read[Tab]表示我在輸入read之後又按下了Tab鍵(開始需要按兩次,後續只需按一次)。這主要是爲了讓你更加清晰地看到輸入與回顯間的關係。

可以看到,在我輸入read[Tab]之後,REPL 環境爲我提供了很多可選的程序定義。這些都是函數,並且名稱都是以read爲前綴的。也就是說,我們記不住程序定義的全名沒有關係,只要知道開頭的幾個字母就可以了。剩下的完全可以交給代碼補全這個助手。另外,我們也可以利用這一功能進行編程的學習。就像前面展示的那樣,我們可以藉此瞭解到所有與“讀”有關的函數都有哪些。

不僅如此,我們還可以利用代碼補全功能即時地查詢函數的使用方法,例如:

julia> filter([Tab]
filter(f, a::Array{T,1} where T) in Base at array.jl:2351
filter(f, Bs::BitArray) in Base at bitarray.jl:1710
filter(f, As::AbstractArray) in Base at array.jl:2312
filter(f, d::AbstractDict) in Base at abstractdict.jl:389
filter(pred, s::AbstractSet) in Base at abstractset.jl:332
filter(f, s::AbstractString) in Base at strings/basic.jl:581
julia> filter(

我在輸入filter(之後又按下了Tab鍵,這樣就可以看到filter函數以及從它衍生出的各種方法了。回顯內容中也包含了每個函數或方法所在的模塊和源碼文件。

順便說一下,在 Julia 語言中,函數代表的可以是一種泛化的功能。而能夠作用於特定類型的參數的那些具體實現被稱爲方法。藉助多重分派機制,Julia 可以根據我們在調用函數時給予的參數值的類型找到對應的方法並完成調用過程。對於上述示例,最前面展示的filter(f, a::Array{T,1} where T)代表的就是泛化的函數,而在它下面的那幾個代表的就是具體的方法。

另外,Tab鍵還可以對字符串中的文件路徑進行補全,比如:

julia> path = "/usr/[Tab]"
bin/        lib/         libexec/     local/       sbin/        share/       standalone/
julia> path = "/usr/"

以上這些只是對Tab鍵的主要使用場景進行了簡要的說明。這個代碼補全的功能實際上比這裏展示的更加強大。不過,其餘的就留給你在 REPL 環境中自行探索吧。

到這裏,我們已經講了很多關於 REPL 環境的使用方法,包括:基本的表達式求值、4 種主要模式、常用的快捷鍵、代碼補全功能等。除此之外 ,REPL 環境還支持複雜代碼(比如含有流程控制語句的代碼)的輸入和求值。有了這些,你基本上就可以玩轉 Julia 的 REPL 環境了,並且可以利用它大幅提高你的編程效率。

2.2 程序包與環境配置

我們已經知道,在 REPL 環境的 pkg 模式中,我們可以通過add命令安裝新的程序包。那麼,這些新的程序包都被存儲到哪裏了呢?

2.2.1 倉庫目錄

說到程序包的存儲,就不得不提及 Julia 的項目環境(project environment)了。在這個項目環境下,包含了一組倉庫目錄。這些目錄的路徑會被包含在全局數組DEPOT_PATH中。比如,在我的 macOS 操作系統中,這個數組的信息如下:

julia> DEPOT_PATH
3-element Array{String,1}:
 "/Users/haolin/.julia"                                                  
 "/Applications/Julia-1.1.app/Contents/Resources/julia/local/share/julia"
 "/Applications/Julia-1.1.app/Contents/Resources/julia/share/julia" 

在默認情況下,我們自己安裝的包都會被存儲到第一個倉庫目錄的packages子目錄中。在這裏,該目錄的路徑是/Users/haolin/.julia/packages。我們可以稱之爲程序包存儲目錄。Julia 在爲我們查找程序包的時候就會進入到這裏。

順便說一句,以/Applications/Julia-1.1.app開頭的倉庫目錄只會在 macOS 操作系統下出現。如果是在 Linux 操作系統中,這裏的倉庫目錄應該還會有/usr/local/share/julia/usr/share/julia

在程序包存儲目錄裏,每一個程序包都會獨佔一個次級目錄,而這些次級目錄的名稱會與對應程序包的名稱一致。爲了描述方便,我們可以稱這樣的次級目錄爲程序包目錄。

由於 Julia 的程序包管理器(也就是Pkg包中的程序)允許我們安裝名稱相同但實則不同的多個程序包,所以在這些程序包目錄中至少還會有一個再次一級的子目錄。這些目錄的命名看起來並沒有什麼規律。比如:

$ ls ~/.julia/packages/JSON
Hs3Dj ebvl3

可以看到,在程序包目錄JSON中,還有Hs3Djebvl3這兩個子目錄。實際上,此類子目錄的名稱是 Julia 根據程序包的具體信息(如 UUID 和源碼倉庫地址的哈希值)計算得出的唯一識別碼。官方把這種識別碼叫做 slug。因此,我們可以把這些再次一級的子目錄稱爲 slug 目錄。

2.2.2 環境配置

現在,讓我們再把焦點擴散開來,並考慮一個問題:我們可以直接使用倉庫目錄中的所有程序包嗎?你可能會想,既然程序包已經在這裏了,那肯定是可以的。可事實並非如此。這又涉及到 項目環境包含的另一部分——環境配置。

Julia 的環境配置一般由兩個配置文件代表,即:Project.tomlManifest.toml。前者叫做項目文件,後者叫做清單文件。對於 Julia 的全局環境配置,這兩個文件通常會被存儲到~/.julia/environments目錄中。又由於不同特性版本的 Julia 都會有獨立的全局環境配置,所以對於特性版本爲v1.1的 Julia 來說,它的全局環境配置文件會被保存在~/.julia/environments/v1.1目錄下。

那麼,什麼是環境配置?全局環境配置又是什麼意思呢?這裏的環境配置是指,用於確定 Julia 程序的依賴關係和規則的配置。更具體地說,它會規定用戶編寫的 Julia 程序在當前的項目環境下可以導入(import)或使用(using)哪些程序包。並且,環境配置還會幫助我們記錄項目中程序的完整依賴關係圖。

Julia 會把自身的安裝環境看做是一個全局項目。顯然,這個全局項目對於當前的 Julia 安裝來說就是全局的。因此,針對此項目的環境配置就是我在前面所說的全局環境配置。其中配置的依賴規則主要針對於:

  • 在 REPL 環境下輸入的 Julia 代碼。
  • 不屬於其他項目的獨立的 Julia 程序。

舉個例子。當我們在 REPL 環境中安裝第一個程序包的時候,在程序包存儲目錄中就會出現相應的程序包目錄。比如,我在 REPL 環境下第一次安裝一個名叫DataFrames的程序包:

(v1.1) pkg> add DataFrames
   Cloning default registries into `~/.julia`
   Cloning registry from "https://github.com/JuliaRegistries/General.git"
     Added registry `General` to `~/.julia/registries/General`
 Resolving package versions...
 # 省略一些輸出,此處會顯示安裝了哪些程序包。
  Updating `~/.julia/environments/v1.1/Project.toml`
  [a93c6f00] + DataFrames v0.18.3
  Updating `~/.julia/environments/v1.1/Manifest.toml`
  # 省略一些輸出,此處會顯示清單文件的更新細節。

在安裝完成後,我的~/.julia/packages目錄的內容是這樣的:

$ ls ~/.julia/packages
CategoricalArrays           JSON                        Requires
Compat                      Missings                    SortingAlgorithms
DataFrames                  OrderedCollections          StatsBase
DataStructures              PooledArrays                TableTraits
IteratorInterfaceExtensions Reexport                    Tables

可以看到,除了DataFrames之外,其中還包括了一些我們未曾相識的程序包目錄。這些目錄所代表的程序包實際上是DataFrames包的依賴包。在當前的項目環境下,這些程序包可以被DataFrames包使用,但卻不能被我們編寫的程序直接使用。爲什麼這麼說呢?我們先來看一下當前環境中的項目文件(~/.julia/environments/v1.1/Project.toml)的內容:

[deps]
DataFrames = "a93c6f00-e57d-5684-b7b6-d8193f3e46c0"

此項目文件的[deps]部分會羅列我們顯式安裝的所有程序包的名稱和 UUID。顯而易見,這裏只有DataFrames包。Julia 規定,環境配置所針對的項目中的程序只能直接依賴在該配置的項目文件中出現的那些程序包。

因此,當我們想在 REPL 環境下導入JSON包的時候,就會出現如下的情況:

julia> import JSON
ERROR: ArgumentError: Package JSON not found in current path:
- Run `import Pkg; Pkg.add("JSON")` to install the JSON package.

Stacktrace:
 [1] require(::Module, ::Symbol) at ./loading.jl:823

julia> 

Julia 向我們報告了錯誤並提示“在當前的路徑下沒有找到JSON包”,並且還告訴我們“可以通過調用Pkg包的add函數顯式地安裝這個包。這正是由於在當前環境的項目文件中並沒有JSON包的記錄而導致的。

順便說一句,在 REPL 環境中,在 julia 模式下通過調用Pkg.add函數安裝程序包與在 pkg 模式下通過add命令安裝程序包是等同的。

下面,我們就按照 Julia 的提示安裝JSON包:

julia> import Pkg; Pkg.add("JSON")
 Resolving package versions...
  Updating `~/.julia/environments/v1.1/Project.toml`
  [682c06a0] + JSON v0.20.0
  Updating `~/.julia/environments/v1.1/Manifest.toml`
 [no changes]

julia> 

由於JSON包已經存在於程序包存儲目錄中了,所以 Julia 無需再次下載。它只需要更新一下環境配置的文件即可。並且,由於這些程序包之間的依賴關係並沒有改變,所以清單文件也沒有任何變化。

現在,項目文件中的內容變爲了:

[deps]
DataFrames = "a93c6f00-e57d-5684-b7b6-d8193f3e46c0"
JSON = "682c06a0-de6a-54ab-a142-c8b1cf79cde6"

我們此時再在 REPL 環境中直接導入JSON包就沒有任何問題了:

julia> import JSON
[ Info: Precompiling JSON [682c06a0-de6a-54ab-a142-c8b1cf79cde6]

julia> 

順便說一句,在我們第一次導入JSON包的時候,Julia 會先對該包進行預編譯。這主要是爲了讓代碼跑得更快。

2.3 項目的創建與引入

到目前爲止,我們已經對 Julia 的項目環境有了一定的瞭解,並討論了倉庫目錄、程序包存儲目錄和環境配置這幾個重要的概念。

項目的環境配置一般由項目文件Project.toml和清單文件Manifest.toml體現。全局環境配置針對的是 REPL 環境中的代碼和獨立的 Julia 程序。該環境配置的文件通常會在~/.julia/environments目錄的特性版本子目錄(如v1.1)中。

我們已經學會了在全局環境中怎樣安裝和導入程序包。這對於編寫和部署一些腳本程序來說已經足夠了。不過,我們在正式開發 Julia 項目的時候往往還需要專屬的環境配置文件。這樣才能與全局環境區別開。這麼做有 3 個好處:

  1. 一旦有了專屬的環境配置文件,我們的項目就可以獨立地管理依賴包了。
  2. 針對某個 Julia 項目的程序包管理操作不會影響到全局的環境配置。反之亦然。
  3. 擁有環境配置文件的 Julia 項目可以爲項目的分發(以供他人使用)做好準備。

換句話說,我們的 Julia 項目可以因此成爲獨立的、可重用的以及對分發友好的項目。

2.3.1 項目的創建

創建一個 Julia 項目很容易,在 REPL 環境中就可以辦到。我們先在命令行中通過輸入julia命令進入到 REPL 環境。然後,我們在它的 shell 模式中進入某個專用的目錄(比如~/Projects),就像這樣:

shell> cd ~/Projects/
/Users/haolin/Projects

julia> 

這時,我們可以再確認一下當前的目錄:

julia> pwd()
"/Users/haolin/Projects"

julia> 

這裏的pwd是 Print Working Directory 的縮寫。所以,pwd函數的含義就是打印當前的工作目錄。這與在命令行中輸入pwd命令的作用是類似的。只不過調用表達式pwd()的求值結果是一個字符串。

在確認了工作目錄之後,我們就可以切換到 REPL 環境的 pkg 模式,然後輸入generate命令,並後跟一個空格和項目的名稱Programs(你也可以用別的名字):

(v1.1) pkg> generate Programs
Generating project Programs:
    Programs/Project.toml
    Programs/src/Programs.jl

(v1.1) pkg> 

注意,我在generate命令後面追加的參數是我們要創建的 Julia 項目的名稱。隨後,這個命令創建了一個名爲Programs的目錄,並在該目錄下生成了兩個文件。一個是項目文件Project.toml,另一個是src目錄(即源碼目錄)下的源碼文件Programs.jl

我們先來看項目文件,它的內容如下:

name = "Programs"
uuid = "e525bb1a-bb1e-11e9-07f5-1125a61c95e2"
authors = ["robert.hao <[email protected]>"]
version = "0.1.0"

這裏有 4 個條目,分別代表項目的名稱、UUID、作者信息和初始版本號。其中的 UUID 是 Julia 的程序包管理器自動生成的。而項目作者信息是從當前操作系統中的 Git 配置信息複製過來的。

我們再來看源碼文件Programs.jl的內容:

module Programs

greet() = print("Hello World!")

end # module

其中只定義了一個名爲Programs的模塊。並且,該模塊僅包含了一個可以向計算機的標準輸出打印Hello World!的函數greet。這顯然只是一個簡單的程序模板。不過,它爲我們後續的編碼開了個頭。

注意,這個源碼文件是有重要意義的:

  1. 該文件可以被稱爲Programs項目的源碼入口。或者說,它是這個項目的主源碼文件。這是由於該文件的主文件名與項目的(主)名稱是一致的。
  2. 該文件中定義的(最外層的)模塊Programs將會是其所屬項目的主模塊(或者說默認模塊)。這是由於該模塊的名稱與項目的(主)名稱是一致的。

正因爲有了這樣的一個源碼文件,使得Programs項目可以被 Julia 視爲一個程序包。更明確地講,如果存在一個名爲XX.jl的 Julia 項目,只要該項目包含一個相對路徑爲src/X.jl的源碼文件,並且在該文件中定義的最外層模塊名爲X,那麼它就是一個有效的程序包。

最後,一個可選的操作是,我們可以把這個項目的名稱變更爲Programs.jl。如此可以讓它更具 Julia 項目的特色。由前述內容可知,這樣做並不會妨礙此項目成爲一個有效的程序包。注意,項目Programs.jl所代表的程序包的名稱依然是Programs,同時它的主模塊的名稱也依然是Programs

2.3.2 程序包的引入

既然Programs.jl項目已經是一個有效的程序包了,那麼我們就可以在代碼中對它進行引入(更明確地說,是引入它的主模塊Programs)。具體怎麼做呢?

當我們試圖在全局環境中導入該程序包的時候,Julia 會提示找不到這個程序包:

julia> import Programs
ERROR: ArgumentError: Package Programs not found in current path:
- Run `import Pkg; Pkg.add("Programs")` to install the Programs package.

Stacktrace:
 [1] require(::Module, ::Symbol) at ./loading.jl:823

julia> 

爲了解決這個問題,我們可以先在 REPL 環境下進入到Programs.jl項目所在的目錄,然後切換到 pkg 模式,並輸入命令activate .。注意,這裏的輸入是activate加一個空格,再加一個英文點號.。示例如下:

shell> cd ~/Projects/Programs.jl
/Users/haolin/Projects/Programs.jl

(v1.1) pkg> activate .

(Programs) pkg> 

我們可以看到,在使用activate命令之後,REPL 環境的提示符再次改變了,變成了當前程序包的名稱Programs,也就是在當前目錄下的Project.toml文件中記錄的那個名稱。命令activate .的作用正是把程序包管理器的操作目錄切換到當前項目所在的目錄,即:~/Projects/Programs.jl。還記得嗎?它原先的(或者說默認的)操作目錄是~/.julia/environments/v1.1,對應於 Julia 的v1.1版本的全局環境。順便說一下,如果你想切換回全局環境,那麼只需要再次輸入命令activate(不加任何參數)就可以了。

在這之後,我們再在當前的 REPL 環境中導入Programs就不會有問題了:

julia> import Programs
[ Info: Precompiling Programs [e525bb1a-bb1e-11e9-07f5-1125a61c95e2]

julia> Programs.greet()
Hello World!

如果我們確實需要在全局環境中引入Programs,那麼可以先把這個項目上傳到一個代碼託管倉庫(比如 GitHub)中,然後再使用 Julia 的程序包管理器把它安裝到本地的倉庫目錄。

比如,我們的這個Programs.jl項目已經在 GitHub 上了,它的 git 地址是[email protected]:hyper0x/Programs.jl.git。所以,我們現在就可以直接在 REPL 環境中進行如下操作:

(Programs) pkg> activate

(v1.1) pkg> add [email protected]:hyper0x/Programs.jl.git
  Updating registry at `~/.julia/registries/General`
  Updating git-repo `https://github.com/JuliaRegistries/General.git`
   Cloning git-repo `[email protected]:hyper0x/Programs.jl.git`
  Updating git-repo `[email protected]:hyper0x/Programs.jl.git`
 Resolving package versions...
  Updating `~/.julia/environments/v1.1/Project.toml`
  [d2b7efac] + Programs v0.1.0 #master ([email protected]:hyper0x/Programs.jl.git)
  Updating `~/.julia/environments/v1.1/Manifest.toml`
  [d2b7efac] + Programs v0.1.0 #master ([email protected]:hyper0x/Programs.jl.git)

(v1.1) pkg> 

一旦Programs程序包被記錄在了全局環境的項目文件中,我們在該環境下引入它也就不會有問題了。

2.4 小結

在本章,我們一直在討論 Julia 程序的編寫環境。首先,我們詳述了 Julia 語言的 REPL 環境的用法,包括在其中編寫程序的簡單規則、它的主要模式及其使用和切換方法、常用的快捷鍵,以及其中的代碼補全功能。REPL 環境將會是我們編寫 Julia 程序時最常用的。

之後,我們介紹了 Julia 項目環境的概念,並在此基礎上講解了倉庫目錄、程序包存儲目錄、環境配置文件,以及項目的創建和程序包的引入。這些內容都是我們在開發 Julia 項目時必須掌握的。

從下一章開始,我們就要正式地講解 Julia 語言的語法了,包括各種程序定義的寫法以及各式流程控制語句的用法。我相信,在掌握了前面所述的預備知識之後,你可以很輕鬆地開始下一階段的學習。同時,你在之前留下的一些疑慮和問題,也將會在後面被陸續地解開。

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