與其他語言的顯著差異

與 MATLAB 的顯著差異

儘管 MATLAB 使用者可能會覺得 Julia 的語法很熟悉,但 Julia 並非 MATLAB 的複製。兩者在語法和功能上有重大的差異。以下是一些值得注意的差異,可能會讓習慣 MATLAB 的 Julia 使用者感到困擾

  • Julia 陣列使用方括號編制索引,A[i,j]
  • 指派給其他變數時,Julia 陣列不會被複製。在 A = B 之後,變更 B 的元素也會修改 A。若要避免這種情況,請使用 A = copy(B)
  • 傳遞給函式的 Julia 值不會被複製。如果函式修改陣列,變更會在呼叫程式中可見。
  • Julia 陣列不會在指派陳述式中自動擴充。在 MATLAB 中,a(4) = 3.2 可以建立陣列 a = [0 0 0 3.2],而 a(5) = 7 可以將其擴充為 a = [0 0 0 3.2 7],對應的 Julia 陳述式 a[5] = 7 會擲回錯誤,如果 a 的長度小於 5,或者此陳述式是識別碼 a 的第一次使用。Julia 有 push!append!,它們能比 MATLAB 的 a(end+1) = val 更有效率地擴充 Vector
  • 虛數單位 sqrt(-1) 在 Julia 中表示為 im,而非 MATLAB 中的 ij
  • 在 Julia 中,沒有小數點的數字字面值(例如 42)會建立整數,而非浮點數。因此,如果某些運算預期浮點數,可能會擲回網域錯誤;例如,julia> a = -1; 2^a 會擲回網域錯誤,因為結果不是整數(詳情請參閱 關於網域錯誤的常見問題解答條目)。
  • 在 Julia 中,多個值會以元組的形式回傳並指派,例如 (a, b) = (1, 2)a, b = 1, 2。MATLAB 的 nargout,它經常在 MATLAB 中用於根據回傳值的數量來執行選擇性工作,在 Julia 中不存在。相反地,使用者可以使用選擇性參數和關鍵字參數來達成類似的功能。
  • Julia 具有真正的單維陣列。列向量的大小為 N,而不是 Nx1。例如,rand(N) 會建立一個單維陣列。
  • 在 Julia 中,[x,y,z] 將永遠建構一個包含 xyz 的 3 元素陣列。
    • 要在第一個(「垂直」)維度中串接,請使用 vcat(x,y,z) 或以分號分隔([x; y; z])。
    • 要在第二個(「水平」)維度中串接,請使用 hcat(x,y,z) 或以空格分隔([x y z])。
    • 要建構區塊矩陣(在頭兩個維度中串接),請使用 hvcat 或結合空格和分號([a b; c d])。
  • 在 Julia 中,a:ba:b:c 建構 AbstractRange 物件。若要建構一個像 MATLAB 中的完整向量,請使用 collect(a:b)。不過,通常不需要呼叫 collect。在大部分情況下,AbstractRange 物件會像一般陣列一樣運作,但它會延遲計算其值,因此更有效率。這種建立特殊物件而非完整陣列的模式經常使用,也見於函式中,例如 range,或迭代器中,例如 enumeratezip。這些特殊物件大多可以用作一般陣列。
  • Julia 中的函式會從其最後一個表達式或 return 關鍵字傳回值,而不是在函式定義中列出要傳回的變數名稱(詳細資訊請參閱 The return Keyword)。
  • Julia 程式碼可以包含任意數量的函式,且當載入檔案時,所有定義都會對外可見。函式定義可以從目前工作目錄以外的檔案載入。
  • 在 Julia 中,當使用單一引數呼叫時,會對陣列的每個元素執行簡約運算,例如 sumprodmax,例如 sum(A),即使 A 有多個維度。
  • 在 Julia 中,必須使用括弧來呼叫沒有引數的函式,例如 rand()
  • Julia 不建議使用分號來結束陳述式。陳述式的結果不會自動列印(互動式提示字元除外),且程式碼列不需要以分號結尾。可以透過 println@printf 來列印特定輸出。
  • 在 Julia 中,如果 AB 是陣列,邏輯比較運算式(例如 A == B)不會傳回布林陣列。請改用 A .== B,其他布林運算子(例如 <>)也一樣。
  • 在 Julia 中,運算子 &| (xor) 分別執行等同於 MATLAB 中 andorxor 的位元運算,優先順序類似於 Python 的位元運算子(與 C 不同)。它們可以在純量或陣列中逐元素運算,也可以用來組合邏輯陣列,但請注意運算順序的差異:可能需要括號(例如,要選取等於 1 或 2 的 A 元素,請使用 (A .== 1) .| (A .== 2))。
  • 在 Julia 中,集合的元素可以使用散佈運算子 ... 作為引數傳遞給函式,例如 xs=[1,2]; f(xs...)
  • Julia 的 svd 會傳回奇異值向量,而不是稠密對角矩陣。
  • 在 Julia 中,... 不用於繼續程式碼行。相反地,未完成的表達式會自動繼續到下一行。
  • 在 Julia 和 MATLAB 中,變數 ans 會設定為互動式工作階段中發出的最後一個表達式的值。與 MATLAB 不同,在 Julia 中,當 Julia 程式碼以非互動模式執行時,不會設定 ans
  • 與 MATLAB 的 class 不同,Julia 的 struct 不支援在執行階段動態新增欄位。請改用 Dict。Julia 中的 Dict 沒有順序。
  • 在 Julia 中,每個模組都有自己的全域範圍/名稱空間,而在 MATLAB 中只有一個全域範圍。
  • 在 MATLAB 中,移除不需要值的慣用語法是使用邏輯索引,例如在表達式 x(x>3) 中或在陳述式 x(x>3) = [] 中來修改 x。相較之下,Julia 提供高階函式 filterfilter!,讓使用者可以撰寫 filter(z->z>3, x)filter!(z->z>3, x) 作為對應的轉譯 x[x.>3]x = x[x.>3] 的替代方案。使用 filter! 可以減少暫時陣列的使用。
  • 擷取(或「解除參考」)儲存格陣列所有元素的類比,例如在 MATLAB 中的 vertcat(A{:}),在 Julia 中使用散佈運算子撰寫,例如 vcat(A...)
  • 在 Julia 中,adjoint 函式執行共軛轉置;在 MATLAB 中,adjoint 提供「伴隨矩陣」或經典伴隨矩陣,也就是餘因子矩陣的轉置。
  • 在 Julia 中,a^b^c 會評估為 a^(b^c),而在 MATLAB 中會評估為 (a^b)^c。

與 R 的顯著差異

Julia 的目標之一是提供一種有效的語言來進行資料分析和統計程式設計。對於從 R 轉換到 Julia 的使用者,以下是一些顯著的差異

  • Julia 的單引號括住字元,而不是字串。

  • Julia 可以透過索引字串來建立子字串。在 R 中,必須先將字串轉換為字元向量才能建立子字串。

  • 在 Julia 中,就像 Python 但不像 R,字串可以使用三引號 """ ... """ 建立。此語法對於建立包含換行符號的字串很方便。

  • 在 Julia 中,變數長度參數使用擴散運算子 ... 指定,它總是跟在特定變數名稱之後,這與 R 不同,後者中 ... 可以單獨出現。

  • 在 Julia 中,模數是 mod(a, b),而不是 a %% b。Julia 中的 % 是取餘運算子。

  • Julia 使用方括號建立向量。Julia 的 [1, 2, 3] 等同於 R 的 c(1, 2, 3)

  • 在 Julia 中,並非所有資料結構都支援邏輯索引。此外,Julia 中的邏輯索引僅支援長度等於被索引物件的向量。例如

    • 在 R 中,c(1, 2, 3, 4)[c(TRUE, FALSE)] 等同於 c(1, 3)
    • 在 R 中,c(1, 2, 3, 4)[c(TRUE, FALSE, TRUE, FALSE)] 等同於 c(1, 3)
    • 在 Julia 中,[1, 2, 3, 4][[true, false]] 會擲出 BoundsError
    • 在 Julia 中,[1, 2, 3, 4][[true, false, true, false]] 會產生 [1, 3]
  • 與許多語言一樣,Julia 不總是允許對不同長度的向量進行運算,這與 R 不同,後者中向量只需要共用一個共同的索引範圍即可。例如,c(1, 2, 3, 4) + c(1, 2) 在 R 中是有效的,但等效的 [1, 2, 3, 4] + [1, 2] 會在 Julia 中擲出錯誤。

  • 當逗號不改變程式碼的意義時,Julia 允許使用可選的尾隨逗號。這可能會讓 R 使用者在索引陣列時感到困惑。例如,R 中的 x[1,] 會傳回矩陣的第一列;然而,在 Julia 中,逗號會被忽略,因此 x[1,] == x[1],並且會傳回第一個元素。若要擷取列,請務必使用 :,例如 x[1,:]

  • Julia 的 map 先取函式,然後再取其引數,這與 R 中的 lapply(<structure>, function, ...) 不同。類似地,Julia 中等效於 R 中 apply(X, MARGIN, FUN, ...) 的是 mapslices,其中函式是第一個引數。

  • R 中的多變數套用,例如 mapply(choose, 11:13, 1:3),可以在 Julia 中寫成 broadcast(binomial, 11:13, 1:3)。同樣地,Julia 提供了更簡短的點語法來向量化函式 binomial.(11:13, 1:3)

  • Julia 使用 end 來表示條件區塊的結尾,例如 if,迴圈區塊,例如 while/ for,以及函式。Julia 允許 if cond; statement; endcond && statement!cond || statement 等形式的陳述式,取代單行的 if ( cond ) statement。後兩者語法中的賦值陳述式必須明確地用括號包起來,例如 cond && (x = value)

  • 在 Julia 中,<-<<--> 不是賦值運算子。

  • Julia 的 -> 會建立一個匿名函式。

  • Julia 的 * 運算子可以執行矩陣乘法,這與 R 不同。如果 AB 是矩陣,則 A * B 表示 Julia 中的矩陣乘法,等於 R 中的 A %*% B。在 R 中,此相同符號會執行元素乘法(Hadamard 乘法)。若要取得元素乘法運算,您需要在 Julia 中寫成 A .* B

  • Julia 使用 transpose 函式執行矩陣轉置,並使用 ' 運算子或 adjoint 函式執行共軛轉置。因此,Julia 的 transpose(A) 等於 R 的 t(A)。此外,Julia 中的非遞迴轉置是由 permutedims 函式提供的。

  • Julia 在撰寫 if 陳述式或 for/while 迴圈時不需要括號:使用 for i in [1, 2, 3] 取代 for (i in c(1, 2, 3)),並使用 if i == 1 取代 if (i == 1)

  • Julia 沒有將數字 01 視為布林值。您不能在 Julia 中寫入 if (1),因為 if 陳述式只接受布林值。相反地,您可以寫入 if trueif Bool(1)if 1==1

  • Julia 不提供 nrowncol。請改用 size(M, 1) 取代 nrow(M),並用 size(M, 2) 取代 ncol(M)

  • Julia 仔細區分純量、向量和矩陣。在 R 中,1c(1) 是相同的。在 Julia 中,它們不能互換使用。

  • Julia 的 diagdiagm 與 R 的不同。

  • Julia 無法將函式呼叫的結果指定給指定作業運算的左手邊:您無法撰寫 diag(M) = fill(1, n)

  • Julia 不鼓勵在主命名空間中填入函式。Julia 的大多數統計功能都可以在 套件 中找到,這些套件位於 JuliaStats 組織 中。例如

  • Julia 提供元組和真正的雜湊表,但不提供 R 風格的清單。傳回多個項目時,您通常應該使用元組或命名元組:請改用 (1, 2)(a=1, b=2),不要使用 list(a = 1, b = 2)

  • Julia 鼓勵使用者撰寫自己的類型,這些類型比 R 中的 S3 或 S4 物件更容易使用。Julia 的多重分派系統表示 table(x::TypeA)table(x::TypeB) 會像 R 的 table.TypeA(x)table.TypeB(x) 一樣作用。

  • 在 Julia 中,指派或傳遞給函式時不會複製值。如果函式修改陣列,呼叫者將可以看到變更。這與 R 非常不同,而且讓新函式能夠更有效率地處理大型資料結構。

  • 在 Julia 中,使用 hcatvcathvcat 串聯向量和矩陣,而不是像在 R 中使用 crbindcbind

  • 在 Julia 中,像 a:b 這樣的範圍並非像在 R 中那樣是向量的簡寫,而是一個用於迭代的特殊 AbstractRange 物件。若要將範圍轉換為向量,請使用 collect(a:b)

  • : 算子在 R 和 Julia 中具有不同的優先順序。特別是,在 Julia 中,算術運算子的優先順序高於 : 算子,而在 R 中則相反。例如,Julia 中的 1:n-1 等於 R 中的 1:(n-1)

  • Julia 中的 maxmin 分別等於 R 中的 pmaxpmin,但兩個參數必須具有相同的維度。雖然 maximumminimum 在 R 中取代了 maxmin,但它們之間存在重要的差異。

  • Julia 的 sumprodmaximumminimum 與 R 中的同類函數不同。它們都接受一個可選的關鍵字參數 dims,用於指示執行運算的維度。例如,在 Julia 中 A = [1 2; 3 4],在 R 中 B <- rbind(c(1,2),c(3,4)) 是同一個矩陣。那麼 sum(A) 給出的結果與 sum(B) 相同,但 sum(A, dims=1) 是包含每一列總和的列向量,而 sum(A, dims=2) 是包含每一行總和的列向量。這與 R 的行為形成對比,在 R 中,單獨的 colSums(B)rowSums(B) 函數提供了這些功能。如果 dims 關鍵字參數是一個向量,那麼它指定執行總和的所有維度,同時保留求和數組的維度,例如 sum(A, dims=(1,2)) == hcat(10)。需要注意的是,對於第二個參數沒有錯誤檢查。

  • Julia 有幾個函數可以改變它們的參數。例如,它既有 sort 也有 sort!

  • 在 R 中,效能需要向量化。在 Julia 中,幾乎相反:效能最佳的代碼通常是通過使用非向量化迴圈來實現的。

  • Julia 是熱切求值的,不支持 R 風格的惰性求值。對於大多數使用者來說,這意味著幾乎沒有未加引號的表達式或欄位名稱。

  • Julia 不支援 NULL 類型。最接近的等價物是 nothing,但它的行為更像一個標量值,而不是一個列表。使用 x === nothing 而不是 is.null(x)

  • 在 Julia 中,遺失值由 missing 物件表示,而不是由 NA 表示。使用 ismissing(x)(或 ismissing.(x) 對於向量的元素級運算)而不是 is.na(x)。通常使用 skipmissing 函數代替 na.rm=TRUE(儘管在某些特定情況下,函數會採用 skipmissing 參數)。

  • Julia 沒有 R 的 assignget 等效項。

  • 在 Julia 中,return 不需要括號。

  • 在 R 中,移除不需要值的慣用語法是使用邏輯索引,例如表達式 x[x>3] 或陳述式 x = x[x>3] 來修改 x。相反地,Julia 提供高階函式 filterfilter!,讓使用者可以撰寫 filter(z->z>3, x)filter!(z->z>3, x) 作為對應的轉寫 x[x.>3]x = x[x.>3] 的替代方案。使用 filter! 可以減少暫時陣列的使用。

與 Python 的顯著差異

  • Julia 的 forifwhile 等區塊以 end 關鍵字終止。縮排層級不像 Python 中那樣有意義。與 Python 不同的是,Julia 沒有 pass 關鍵字。
  • 字串在 Julia 中以雙引號表示("text")(多行字串使用三個雙引號),而在 Python 中則可以用單引號('text')或雙引號("text")表示。Julia 中的字元使用單引號('c')。
  • 字串串接在 Julia 中使用 *,而不是像 Python 中的 +。類似的,字串重複使用 ^,而不是 *。Julia 中不會像 Python 中那樣隱式串接字串文字(例如 'ab' 'cd' == 'abcd')。
  • Python 清單(靈活但速度慢)對應到 Julia 的 Vector{Any} 型別,或更通用的 Vector{T},其中 T 是某個非具體元素型別。像 NumPy 陣列那樣儲存元素在原地的「快速」陣列(即 dtypenp.float64[('f1', np.uint64), ('f2', np.int32)] 等)可以用 Array{T} 表示,其中 T 是具體的、不可變的元素型別。這包括內建型別,例如 Float64Int32Int64,但也包括更複雜的型別,例如 Tuple{UInt64,Float64} 以及許多使用者定義的型別。
  • 在 Julia 中,陣列、字串等的索引是從 1 開始,而不是從 0 開始。
  • 與 Python 不同,Julia 的切片索引包含最後一個元素。Julia 中的 a[2:3] 在 Python 中是 a[1:3]
  • 與 Python 不同,Julia 允許 具有任意索引的 AbstractArrays。Python 對負索引的特殊解釋,a[-1]a[-2],在 Julia 中應寫成 a[end]a[end-1]
  • Julia 需要 end 來索引直到最後一個元素。Python 中的 x[1:] 等於 Julia 中的 x[2:end]
  • 在 Julia 中,任何物件前面的 : 會建立一個 Symbol引用一個表達式;因此,x[:5]x[5] 相同。如果您想取得陣列的前 n 個元素,請使用範圍索引。
  • Julia 的範圍索引格式為 x[start:step:stop],而 Python 的格式為 x[start:(stop+1):step]。因此,Python 中的 x[0:10:2] 等於 Julia 中的 x[1:2:10]。類似地,Python 中的 x[::-1],指的是反轉的陣列,等於 Julia 中的 x[end:-1:1]
  • 在 Julia 中,範圍可以獨立建構為 start:step:stop,它在陣列索引中使用相同的語法。range 函數也受支援。
  • 在 Julia 中,使用陣列索引矩陣,例如 X[[1,2], [1,3]],指的是包含第一和第二列與第一和第三列交集的子矩陣。在 Python 中,X[[1,2], [1,3]] 指的是一個向量,其中包含矩陣中單元格 [1,1][2,3] 的值。Julia 中的 X[[1,2], [1,3]] 等於 Python 中的 X[np.ix_([0,1],[0,2])]。Python 中的 X[[0,1], [0,2]] 等於 Julia 中的 X[[CartesianIndex(1,1), CartesianIndex(2,3)]]
  • Julia 沒有換行語法:如果在行的結尾,目前的輸入是一個完整的表達式,則視為完成;否則輸入會繼續。強制表達式繼續的一種方法是用括號將其包起來。
  • Julia 陣列是欄優先(Fortran 順序),而 NumPy 陣列預設是列優先(C 順序)。若要在陣列上執行迴圈時獲得最佳效能,應在 Julia 中反轉迴圈順序(請參閱效能提示中的相關部分)。
  • Julia 的更新運算子(例如 +=-= 等)不是原地運算,而 NumPy 的更新運算子是。這表示 A = [1, 1]; B = A; B += [3, 3] 並不會變更 A 中的值,而是將名稱 B 重新繫結到右手邊 B = B + 3 的結果,也就是一個新的陣列。若要執行原地運算,請使用 B .+= 3(請參閱點運算子)、明確迴圈或 InplaceOps.jl
  • 與 Python 中只在定義函式時評估預設值的作法不同,Julia 會在每次呼叫方法時評估函式引數的預設值。例如,函式 f(x=rand()) = x 會在每次呼叫時沒有引數時傳回一個新的亂數。另一方面,函式 g(x=[1,2]) = push!(x,3) 會在每次呼叫為 g() 時傳回 [1,2,3]
  • 在 Julia 中,關鍵字引數必須使用關鍵字傳遞,與 Python 中通常可以用位置傳遞關鍵字引數不同。嘗試以位置傳遞關鍵字引數會變更方法簽章,導致 MethodError 或呼叫錯誤的方法。
  • 在 Julia 中,% 是餘數運算子,而在 Python 中是模數運算子。
  • 在 Julia 中,常用的 Int 類型對應到機器整數類型 (Int32Int64),這與 Python 中 int 是任意長度整數不同。這表示在 Julia 中,Int 類型會溢位,因此 2^64 == 0。如果您需要較大的值,請使用其他適當的類型,例如 Int128BigInt 或浮點類型,例如 Float64
  • 虛數單位 sqrt(-1) 在 Julia 中表示為 im,而不是 Python 中的 j
  • 在 Julia 中,指數運算子是 ^,而不是 Python 中的 **
  • Julia 使用類型為 Nothingnothing 來表示空值,而 Python 使用類型為 NoneTypeNone
  • 在 Julia 中,矩陣類型上的標準運算子是矩陣運算,而在 Python 中,標準運算子是逐元素運算。當 AB 都是矩陣時,Julia 中的 A * B 執行矩陣乘法,而不是 Python 中的逐元素乘法。Julia 中的 A * B 等於 Python 中的 A @ B,而 Python 中的 A * B 等於 Julia 中的 A .* B
  • Julia 中的共軛運算子 ' 會傳回向量的共軛 (列向量的延遲表示法),而 Python 中向量的轉置運算子 .T 會傳回原始向量 (非運算)。
  • 在 Julia 中,函式可能包含多個具體實作 (稱為「方法」),這些實作會透過多重分派根據呼叫中所有引數的類型來選擇,這與 Python 中的函式不同,Python 中的函式只有一個實作,而且沒有多型性 (與使用不同語法並允許對方法接收者進行分派的 Python 方法呼叫相反)。
  • Julia 中沒有類別。取而代之的是結構 (可變或不可變),其中包含資料但沒有方法。
  • 在 Python 中呼叫類別實例的方法 (x = MyClass(*args); x.f(y)) 對應到 Julia 中的函式呼叫,例如 x = MyType(args...); f(x, y)。一般來說,多重分派比 Python 類別系統更靈活且更強大。
  • Julia 結構可能只有一個抽象的超類型,而 Python 類別可以繼承一個或多個(抽象或具體)的超類別。
  • Julia 的邏輯程式結構(套件和模組)與檔案結構(包含其他檔案的 include)無關,而 Python 程式碼結構則由目錄(套件)和檔案(模組)定義。
  • Julia 中的三元運算子 x > 0 ? 1 : -1 對應於 Python 中的條件式 1 if x > 0 else -1
  • 在 Julia 中,@ 符號表示巨集,而在 Python 中則表示裝飾器。
  • Julia 中的例外處理使用 trycatchfinally,而不是 tryexceptfinally。與 Python 相反,不建議在 Julia 的正常工作流程中使用例外處理(與 Python 相比,Julia 在一般控制流程中較快,但在例外捕捉中較慢)。
  • Julia 中的迴圈很快,不需要為了效能而撰寫「向量化」程式碼。
  • 小心 Julia 中的非常數全域變數,特別是在緊密迴圈中。由於可以在 Julia 中撰寫接近金屬的程式碼(與 Python 不同),因此全域變數的影響可能會很劇烈(請參閱 效能提示)。
  • 在 Julia 中,捨入和截斷是明確的。Python 的 int(3.7) 應該是 floor(Int, 3.7)Int(floor(3.7)),並且與 round(Int, 3.7) 不同。floor(x)round(x) 本身會傳回與 x 相同類型的整數值,而不是總是傳回 Int
  • 在 Julia 中,解析是明確的。Python 的 float("3.7") 在 Julia 中會是 parse(Float64, "3.7")
  • 在 Python 中,大部分值都可以在邏輯語境中使用(例如:if "a": 表示執行後面的區塊,而 if "": 表示不執行)。在 Julia 中,你需要明確轉換為 Bool(例如:if "a" 會擲出例外)。如果你想在 Julia 中測試非空字串,你可以明確寫成 if !isempty("")。或許令人驚訝的是,在 Python 中 if "False"bool("False") 都會評估為 True(因為 "False" 是非空字串);在 Julia 中,parse(Bool, "false") 會傳回 false
  • 在 Julia 中,大部分程式碼區塊都會引入新的區域範圍,包括迴圈和 trycatchfinally。請注意,在 Python 和 Julia 中,解析(清單、產生器等)都會引入新的區域範圍,而 if 區塊在兩種語言中都不會引入新的區域範圍。

值得注意的與 C/C++ 的差異

  • Julia 陣列使用方括號索引,並且可以有多個維度 A[i,j]。此語法不僅僅是 C/C++ 中對指標或位址參照的語法糖。請參閱 關於陣列建構的手冊條目
  • 在 Julia 中,陣列、字串等的索引是從 1 開始,而不是從 0 開始。
  • Julia 陣列在指定給另一個變數時不會複製。在 A = B 之後,變更 B 的元素也會修改 A。更新運算子(例如 +=)不會就地運算,它們等於 A = A + B,這會將左側重新繫結到右側表達式的結果。
  • Julia 陣列是欄優先(Fortran 順序),而 C/C++ 陣列預設是列優先。要在迴圈陣列時獲得最佳效能,應在 Julia 中反轉迴圈順序(請參閱 效能秘訣中的相關章節)。
  • Julia 值在指派或傳遞至函數時不會被複製。如果函數修改陣列,變更將會在呼叫者中可見。
  • 在 Julia 中,空白字元具有意義,這與 C/C++ 不同,因此在 Julia 程式中新增/移除空白字元時必須小心。
  • In Julia, literal numbers without a decimal point (such as 42) create signed integers, of type Int, but literals too large to fit in the machine word size will automatically be promoted to a larger size type, such as Int64 (if Int is Int32), Int128, or the arbitrarily large BigInt type. There are no numeric literal suffixes, such as L, LL, U, UL, ULL to indicate unsigned and/or signed vs. unsigned. Decimal literals are always signed, and hexadecimal literals (which start with 0x like C/C++), are unsigned, unless when they encode more than 128 bits, in which case they are of type BigInt. Hexadecimal literals also, unlike C/C++/Java and unlike decimal literals in Julia, have a type based on the length of the literal, including leading 0s. For example, 0x0 and 0x00 have type UInt8, 0x000 and 0x0000 have type UInt16, then literals with 5 to 8 hex digits have type UInt32, 9 to 16 hex digits type UInt64, 17 to 32 hex digits type UInt128, and more that 32 hex digits type BigInt. This needs to be taken into account when defining hexadecimal masks, for example ~0xf == 0xf0 is very different from ~0x000f == 0xfff0. 64 bit Float64 and 32 bit Float32 bit literals are expressed as 1.0 and 1.0f0 respectively. Floating point literals are rounded (and not promoted to the BigFloat type) if they can not be exactly represented. Floating point literals are closer in behavior to C/C++. Octal (prefixed with 0o) and binary (prefixed with 0b) literals are also treated as unsigned (or BigInt for more than 128 bits).
  • 在 Julia 中,除法運算子 / 在兩個運算元都是整數型別時,會傳回浮點數。若要執行整數除法,請使用 div÷
  • 在 Julia 中,使用浮點型別索引 Array 通常會產生錯誤。C 語句 a[i / 2] 在 Julia 中的等效語法為 a[i ÷ 2 + 1],其中 i 為整數型別。
  • 字串文字可以用 """" 分隔,""" 分隔的文字可以包含 " 字元,而不用加上引號,例如 "\""。字串文字可以插入其他變數或運算式的值,用 $變數名稱$(運算式) 表示,這會在函數的內容中評估變數名稱或運算式。
  • // 表示 Rational 數字,而不是單行註解(在 Julia 中為 #
  • #= 表示多行註解的開頭,=# 表示結尾。
  • Julia 中的函數會從最後一個運算式或 return 關鍵字傳回值。函數可以傳回多個值,並指定為組,例如 (a, b) = myfunction()a, b = myfunction(),而不是像在 C/C++ 中必須傳遞指標至值(例如 a = myfunction(&b))。
  • Julia 不需要使用分號來結束陳述式。表達式的結果並不會自動列印(互動式提示字元除外,也就是 REPL),而且程式碼行也不需要以分號結尾。println@printf 可用於列印特定輸出。在 REPL 中,; 可用於抑制輸出。;[ ] 中也有不同的意思,這是需要注意的地方。; 可用於分隔單一行上的表達式,但在許多情況下並非絕對必要,而且更像是可讀性的輔助工具。
  • 在 Julia 中,運算子 (xor) 執行位元 XOR 運算,也就是 C/C++ 中的 ^。此外,位元運算子的優先順序與 C/C++ 不同,因此可能需要使用括號。
  • Julia 的 ^ 是指數運算(pow),而不是像 C/C++ 中的位元 XOR(在 Julia 中請使用 xor
  • Julia 有兩個右位移運算子,>>>>>>> 執行算術位移,>>> 始終執行邏輯位移,這與 C/C++ 不同,在 C/C++ 中 >> 的意義取決於被位移值的類型。
  • Julia 的 -> 會建立一個匿名函式,它並不會透過指標存取成員。
  • Julia 在撰寫 if 陳述式或 for/while 迴圈時不需要括號:使用 for i in [1, 2, 3] 取代 for (int i=1; i <= 3; i++),使用 if i == 1 取代 if (i == 1)
  • Julia 沒有將數字 01 視為布林值。您不能在 Julia 中寫入 if (1),因為 if 陳述式只接受布林值。相反地,您可以寫入 if trueif Bool(1)if 1==1
  • Julia 使用 end 表示條件區塊的結尾,例如 if,迴圈區塊,例如 while/ for,以及函式。Julia 允許使用 if cond; statement; endcond && statement!cond || statement 等形式的陳述式,以取代單行 if ( cond ) statement。後兩者語法的賦值陳述式必須明確地用括號包起來,例如 cond && (x = value),這是因為運算子優先順序的關係。
  • Julia 沒有換行語法:如果在行的結尾,目前的輸入是一個完整的表達式,則視為完成;否則輸入會繼續。強制表達式繼續的一種方法是用括號將其包起來。
  • Julia 巨集會對已解析的表達式進行運算,而不是程式碼文字,這讓它們可以對 Julia 程式碼執行複雜的轉換。巨集名稱以 @ 字元開頭,並同時具備函式類型的語法 @mymacro(arg1, arg2, arg3) 和陳述式類型的語法 @mymacro arg1 arg2 arg3。這些形式可以互換;函式類型的形式特別適用於巨集出現在另一個表達式中時,而且通常最為清楚。陳述式類型的形式通常用於註解區塊,例如在分散式 for 結構中:@distributed for i in 1:n; #= body =#; end。在巨集結構的結尾可能不明確時,請使用函式類型的形式。
  • Julia 有列舉類型,使用巨集 @enum(name, value1, value2, ...) 表示。例如:@enum(Fruit, banana=1, apple, pear)
  • 依慣例,修改其參數的函數名稱末端會加上 !,例如 push!
  • 在 C++ 中,預設為靜態調度,也就是說,你需要將函數註解為虛擬函數,才能進行動態調度。另一方面,在 Julia 中,每個方法都是「虛擬的」(儘管它比這更廣義,因為方法會針對每個參數類型進行調度,而不僅是 this,使用最具體宣告規則)。

Julia ⇔ C/C++:命名空間

  • C/C++ namespace 大致對應到 Julia module
  • Julia 中沒有私有全域變數或欄位。所有內容都可以透過完全限定路徑(或相對路徑,如果需要)公開存取。
  • using MyNamespace::myfun(C++)大致對應到 import MyModule: myfun(Julia)。
  • using namespace MyNamespace(C++)大致對應到 using MyModule(Julia)
    • 在 Julia 中,只有 export 的符號會提供給呼叫模組。
    • 在 C++ 中,只有包含在包含(公開)標頭檔中的元素會提供出來。
  • 注意事項:import/using 關鍵字(Julia)也會載入模組(見下文)。
  • 注意事項:import/using(Julia)僅在全域範圍層級(module)中運作
    • 在 C++ 中,using namespace X 在任意範圍內運作(例如:函數範圍)。

Julia ⇔ C/C++:模組載入

  • 當你想到 C/C++「函式庫」時,你可能會尋找 Julia「套件」。
    • 注意事項:C/C++ 函式庫通常包含多個「軟體模組」,而 Julia「套件」通常只包含一個。
    • 提醒:Julia module 是全域範圍(不一定是「軟體模組」)。
  • 取代建置/make 腳本,Julia 使用「專案環境」(有時稱為「專案」或「環境」)。
    • 建置腳本僅供較複雜的應用程式(例如需要編譯或下載 C/C++ 可執行檔的應用程式)使用。
    • 要在 Julia 中開發應用程式或專案,您可以將其根目錄初始化為「專案環境」,並將應用程式特定的程式碼/套件置於其中。這能有效控制專案相依性,並利於日後重現。
    • 可用的套件會透過 Pkg.add() 函數或 Pkg REPL 模式加入「專案環境」。(不過,這不會載入所述套件)。
    • 「專案環境」中可用的套件清單(直接相依性)會儲存在其 Project.toml 檔案中。
    • 「專案環境」的完整相依性資訊會由 Pkg.resolve() 自動產生並儲存在其 Manifest.toml 檔案中。
  • 可供「專案環境」使用的套件(「軟體模組」)會透過 importusing 載入。
    • 在 C/C++ 中,您會使用 #include <moduleheader> 來取得物件/函數宣告,並在建置可執行檔時連結至函式庫。
    • 在 Julia 中,再次呼叫 using/import 僅會將現有模組納入範圍,但不會再次載入(類似於在 C/C++ 中加入非標準的 #pragma once)。
  • 基於目錄的套件存放庫(Julia)可以透過將存放庫路徑加入 Base.LOAD_PATH 陣列來提供。
    • 來自基於目錄的存放庫的套件在透過 importusing 載入之前不需要 Pkg.add() 工具。它們只會提供給專案使用。
    • 基於目錄的套件存放庫是開發「軟體模組」的最快解決方案

Julia ⇔ C/C++:組裝模組

  • 在 C/C++ 中,.c/.cpp 檔案會編譯並透過建立/make 指令碼加入函式庫。
    • 在 Julia 中,import [PkgName]/using [PkgName] 陳述式會載入位於套件 [PkgName]/src/ 子目錄中的 [PkgName].jl
    • 反過來,[PkgName].jl 通常會透過呼叫 include "[someotherfile].jl" 來載入相關的原始檔。
  • include "./path/to/somefile.jl" (Julia) 與 #include "./path/to/somefile.jl" (C/C++) 非常類似。
    • 不過 include "..." (Julia) 不用於包含標頭檔(不需要)。
    • 請勿使用 include "..." (Julia) 從其他「軟體模組」載入程式碼(請改用 import/using)。
    • include "path/to/some/module.jl" (Julia) 會在不同的模組中建立相同程式碼的多個版本(建立具有相同名稱的相異類型等)。
    • include "somefile.jl" 通常用於組裝同一個 Julia 套件(「軟體模組」)中的多個檔案。因此,確保檔案僅 include 一次相對容易(沒有 #ifdef 混淆)。

Julia ⇔ C/C++:模組介面

  • C++ 使用「公開」.h/.hpp 檔案公開介面,而 Julia module 則將特定符號標記為 publicexported,供使用者使用。
    • Julia module 通常只透過為現有函式產生新的「方法」來新增功能(例如:Base.push!)。
    • 因此,Julia 套件的開發人員無法依賴標頭檔進行介面文件編寫。
    • Julia 套件的介面通常使用文件字串、README.md、靜態網頁等來描述。
  • 有些開發人員選擇不 export 套件/模組所需的全部符號。
    • 使用者可能會預期透過使用套件/模組名稱來取得這些元件的資格函數/結構/...(例如:MyModule.run_this_task(...))。

Julia ⇔ C/C++:快速參考

軟體概念JuliaC/C++
未命名範圍begin ... end{ ... }
函數範圍function x() ... endint x() { ... }
全域範圍module MyMod ... endnamespace MyNS { ... }
軟體模組Julia「套件」.h/.hpp 檔案<br>+編譯的 somelib.a
組裝<br>軟體模組SomePkg.jl:...<br>import("subfile1.jl")<br>import("subfile2.jl")<br>...$(AR) *.o &rArr; somelib.a
匯入<br>軟體模組匯入 SomePkg#include <somelib><br>+連結到 somelib.a
模組函式庫LOAD_PATH[]、*Git 儲存庫,<br>**自訂套件登錄更多 .h/.hpp 檔案<br>+更大的編譯 somebiglib.a

* Julia 套件管理員支援從單一 Git 儲存庫註冊多個套件。<br> * 這允許使用者將相關套件的函式庫置於單一儲存庫中。<br> ** Julia 登錄主要設計用於提供套件的版本控制和發行。<br> ** 自訂套件登錄可用於建立一種模組函式庫類型。

與 Common Lisp 的顯著差異

  • Julia 預設使用 1 為基礎的陣列索引,而且它也可以處理任意 索引偏移

  • 函數和變數共用同一個命名空間(「Lisp-1」)。

  • 有一個 Pair 類型,但它並非用作 COMMON-LISP:CONS。各種可迭代集合可以在語言的大多數部分中互換使用(例如,展開、元組等)。對於異質元素的集合,Tuple 最接近 Common Lisp 列表。使用 NamedTuple 取代 alist。對於同質類型的較大集合,應使用 ArrayDict

  • 用於建立原型的典型 Julia 工作流程也使用影像的連續操作,這透過 Revise.jl 套件實作。

  • 為了效能,Julia 偏好運算具有 類型穩定性。Common Lisp 從底層機器運算中抽象出來,而 Julia 則更接近它們。例如

    • 使用 / 的整數除法總是會傳回浮點結果,即使計算是精確的。
      • // 總是會傳回有理數結果
      • ÷ 總是會傳回(截斷的)整數結果
    • 支援大整數,但轉換並非自動;一般整數會 溢位
    • 支援複數,但若要取得複數結果,您需要複數輸入
    • 有多個複數和有理數類型,具有不同的組成類型。
  • 模組(命名空間)可以是階層式的。 importusing 具有雙重角色:它們載入程式碼並在命名空間中提供程式碼。僅對模組名稱使用 import 是可行的(大致等同於 ASDF:LOAD-OP)。不需要另外匯出槽位名稱。無法從模組外部指派全域變數(除了使用 eval(mod, :(var = val)) 作為跳脫艙口)。

  • 巨集以 @ 開頭,與 Common Lisp 相比,它們並未無縫整合到語言中;因此,巨集的使用並不像在後者中那樣廣泛。語言支援 巨集 的一種衛生形式。由於表面語法不同,沒有等效於 COMMON-LISP:&BODY 的東西。

  • 所有函數都是泛函的,並使用多重分派。引數清單不必遵循相同的範本,這會導致強大的慣用語法(請參閱 do)。選用和關鍵字引數的處理方式不同。方法歧義並不像在 Common Lisp 物件系統中那樣得到解決,這需要為交集定義更具體的方法。

  • 符號不屬於任何套件,也不包含任何值本身M.var 在模組 M 中評估符號 var

  • 語言完全支援函數式程式設計風格,包括閉包,但這並不總是 Julia 的慣用語法解決方案。修改捕獲變數時,可能需要一些 解決方法 來提高效能。