輕鬆掌握Julia的作用域

2021-09-24 16:35:54 字數 3618 閱讀 9957

從matlab遷移過來的使用者會覺得julia的作用域有點迷。說實話我也繞了幾個彎子。為了避免把讀者帶進概念的漩渦中,本文列舉幾個典型情況,幫助讀者迅速解決作用域的問題。

matlab的作用域包括乙個全域性域和各個函式的區域性域。julia相對更繁瑣,有乙個全域性域和許多態別的區域性域。迴圈體就是一種區域性域,例如:

a =

1for i=1:

2 a +=1

end

會報錯error: loaderror: undefvarerror: a not defined,證明全域性域的變數沒有自動繼承到區域性域中。實際上,julia會智(zhi)能(zhang)地判斷哪些變數自動繼承,規則是:

為解決報錯,增加乙個global標識:

a =

1for i=1:

2 global a

a +=1

end

得到了a = 3。有趣的是global語句放在區域性域的任一位置都可以。

多層迴圈只需要在最外層標識,例如:

a =

1for i=1:

2 global a

for j=1:

3 a +=1

endend

global絕不能放在迴圈體外面,像這樣就會報錯:

a =

1global a

for i=1:

2for j=1:

3 a +=1

endend

這麼一看的確挺迷的,反正記住就行。如果要強行歸納的話,大概就是:global能使迴圈體的區域性域」向外看「,也能使外層迴圈」向裡看「,但不能使全域性域」向裡看「。想刨根問底的話,請參閱let語法的相關文件。

如果只是把全域性變數當作迴圈變數,那就不必加global標識,原因在於我們沒有修改它。例如:

m =

3; n =

0for i=1:m

global n

n +=1

endn

函式的區域性域比迴圈體更複雜一點點,包括兩種情況:(1)函式與迴圈體遵循相同的自動繼承規則,可以直接繼承全域性變數,只要你不在函式裡修改它。例如:

n =

1function g()

return n+

1endg(

)

這時候要注意,如果函式裡有迴圈體,迴圈體會在函式的區域性域中劃分出乙個新的區域性域。例如:

m =

3; n =

0function g

(m)for i=1:m

global n

n +=1

endreturn n

endg

(m)

假如去掉global n就會報錯。所以要時刻提防迴圈體。

(2)如果某個變數被當作引數傳遞,那麼函式會在區域性域中建立乙個同名區域性變數,即按照」傳值「的方式進行傳遞。這樣建立的區域性變數不會影響同名的全域性變數,與上面的」放棄自動繼承「是乙個意思。例如:

t =

1; w =

0function y

(w) w = t

endprintln

("y=",y

(w),

" w="

,w)

輸出是:

julia>

include

("demo.jl")y=

1 w=

0

當然,global標識也可以用在這裡,例如:

t =

1; w =

0function y()

global w

w = t

endprintln

("y=",y

()," w="

,w)

輸出是:

julia>

include

("demo.jl")y=

1 w=

1

struct atomuv

endw = array

(undef,2,

2)function y

(w) w[1,

2]=atom

(0.1

,0.2

) w

endprintln

("y[1]=",y

(w)[1,

2]," w[1]="

,w[1,2

])w

輸出是:

julia>

include

("demoparallel_1.jl")y[

1]=atom

(0.1

,0.2

) w[1]

=atom

(0.1

,0.2

)2×2 array

:#undef atom(0.1, 0.2)

#undef #undef

可見確實是引用而不是傳值。有趣的是,當採取引用策略時,會無視規則強行繼承,例如:

struct atomuv

endn =

10w = array

(undef,2,

2)function y()

w[1,

2]=atom

(0.1

,0.2

) w

endprintln

("y[1]=",y

()[1

,2],

" w[1]="

,w[1,2

])w

經過測試,julia會把結構體、結構體陣列視為」複雜的「,而把普通的數值、數值陣列、共享陣列視為」簡單的「,無論規模大小。舉個結構體的例子:

mutable

struct atomuv

endw =

atom

(0.1

,0.2

)function y

(w) w.u =

0.5 w

endprintln

("y[1]=",y

(w).u,

" w[1]="

,w.u)

有個特別的語法begin...end可以把若干表示式湊在一起。例如:

w = begin

w =1 w +

=0.1

end

它實際上等價於w = ( w = 1; w += 0.1),是後者的分行寫法。這種結構是沒有區域性域的。

這個也不廢話了,跟別的語言乙個意思。

掌握函式執行過程,作用域鏈

我們在了解了全域性 的執行和作用域的提公升後,我們接下來理解比較特殊的函式執行和作用域鏈。被解析,開闢函式記憶體空間,go中引用函式位址。通過全域性 的變數提公升我們知道,在 解析過程中,會生成全域性物件global object go 並在其中對全域性的變數進行定義,函式在這個期間也會被定義,並生...

Javascript的作用域域作用域鏈的理解

如何解析一段可執行 分了兩個階段 解析 和執行 其中解析 可以理解為記名字,就是先把關鍵字var和function定義的變數名登記了下來,這也就有了變數提公升這一說。在執行 階段才是真正的執行賦值,運算等操作。暫不解析這幾個名詞,先來看乙個例子。var scope global function f...

作用域 的作用

1 作用域符號 的前面一般是類名稱,後面一般是該類的成員名稱,c 為例避免不同的類有名稱相同的成員而採用作用域的方式進行區分 如 a,b表示兩個類,在a,b中都有成員member。那麼 a member就表示類a中的成員member b member就表示類b中的成員member 2 全域性作用域符...