官术网_书友最值得收藏!

3.4 理解函數中變量的作用域

當我們在Julia中定義函數時,也可以在函數體內定義變量。在這種情況下,該變量在該函數的局部范圍內有效,因此稱為局部變量。而未在函數體內聲明的變量在全局范圍內有效,因此稱為全局變量。

不同代碼塊中的變量可以使用相同的名稱,但引用的是不同的實體,這種特性就是由其范圍規則所定義的。

Julia有兩種主要的范圍類型:全局范圍和局部范圍。其中局部范圍可以被嵌套。除非另有說明,否則模塊和REPL中的變量通常在全局范圍內;循環、函數、宏、try-catch-finally塊中的變量在局部范圍內。

下面我們用一個例子來解釋局部范圍。

【范例3-14】變量的局部范圍

我們在for結構中定義了一個局部變量hello,并試圖在for結構外輸出它。

01  julia> for i= 1:100
02        hello = i
03      end
04  julia> hello
05  ERROR: UndefVarError: hello not defined

代碼01~03行定義了一個for結構,其中聲明了一個hello變量。在04行我們試圖輸出hello的值,但是卻得到了05行的報錯,報錯類型是未定義變量錯誤,提示hello并沒有被定義。這是為什么呢?

因為對于整個程序來說,for結構屬于一個局部,所以在for結構中聲明的hello僅在for循環的范圍內可用,在for循環的范圍外不可用。

我們修改上一個函數,使得在循環外部也可以訪問到hello。

01  julia> for i=1:100
02        global hello
03        hello = i
04      end
05
06  julia> hello
07  100

這段代碼和范例3-14的代碼幾乎完全一樣,唯一的區別在于添加了02行,用global關鍵字顯式聲明hello為全局變量,這樣就可以在06行要求顯示hello的值時,成功地將hello的值打印出來了。

Julia使用了一種稱為詞法作用域的機制,簡單來說,就是函數的作用域不會從其調用對象的作用域繼承,而是從函數定義的作用域繼承。為了更清楚地理解這一點,我們通過一個例子來說明。

【范例3-15】詞法作用域例子

本例定義了一個模塊,并在模塊外對其進行了調用。

01  julia> module Utility
02      name = "Julia"
03      tell_name() = name
04      end
05  Utility
06
07  julia> name = "Python"
08  "Python"
09
10  julia> Utility.tell_name()
11  "Julia"

代碼01~05行用module關鍵字創建了一個名為“Utility”的模塊,它包含一個name變量和一個tell_name()函數。我們將Utility模塊內的name變量的值設置為“Julia”。為了對比,07行我們在Utility模塊外聲明了另一個name變量,并將它的值設置為“Python”。

在代碼10行,當調用Utility.tell_name()時,我們得到的值是“Julia”。這表明該函數使用了在Utility模塊中定義的name變量的值,這是因為函數tell_name()本身被定義在Utility模塊中。所以,在Utility模塊外聲明的另一個name變量,不會影響函數的運行結果。

Julia還提供了對局部范圍的進一步分類,分為軟局部范圍和硬局部范圍,剛才的函數介紹的是硬局部范圍。我們將在接下來的章節中重新討論范圍,但是現在,我們繼續將注意力放在函數的范圍上。

假設有一個alpha()函數,它的作用是將參數傳遞給一個名為“x”的局部變量并返回x。同時,我們定義了另一個全局變量x,并將它的值設置為100。

【范例3-16】函數范圍

我們在函數內和函數外分別聲明了兩個不同的x變量。

01  julia> x = 100
02  100
03
04  julia> function alpha(n::Int64)
05        x = n
06        return x
07      end
08  alpha (generic function with 1 method)
09
10  julia> alpha(50)
11  50
12
13  # 全局變量x并沒有改變
14  julia> x
15  100

代碼01行定義了一個變量x。04~07行定義了一個函數,在其中定義了另一個變量x,并通過參數賦值的形式對x的值進行了更改。在代碼10行我們對該函數進行了調用,返回的x的值是50。代碼14行直接輸出x的值,輸出的x的值是100。

如果仔細觀察,就會發現x的值自始至終都是100,但是當我們調用alpha(50)函數時,函數返回的是50而不是100。這是因為在函數內部聲明的變量(即函數中的局部變量x)在函數內部被賦值為參數所傳遞的數值(即n),而全局變量x的值對函數內部的局部變量x卻無法直接造成影響。

如果想要在函數內部使用全局聲明的x,該怎么辦呢?我們可以使用global關鍵字。

【范例3-17】在函數內部使用全局變量

我們將函數中的x變量替換為全局的x,然后觀察調用函數后結果發生了怎樣的改變。

01  julia> x = 100
02  100
03
04  julia> function alpha(n::Int64)
05        global x = n
06      end
07  alpha (generic function with 1 method)
08
09  julia> alpha(50)
10  50
11
12  # 全局變量x的值現在被改變了
13  julia> x
14  50

這段代碼和范例3-16的代碼幾乎完全相同,只是在05行函數體內刪除了為局部變量x指定數值的代碼,取而代之的是為全局變量x指定n的值。結果很明顯,和我們所期望的一樣,全局變量x的值已經被改變為50,而不是原始值100了。因為在函數體中我們操作的不再是局部變量x,而是全局變量x。

主站蜘蛛池模板: 迭部县| 乌恰县| 北碚区| 镇雄县| 封丘县| 萨嘎县| 安图县| 阳东县| 彝良县| 江达县| 乌恰县| 莎车县| 澳门| 章丘市| 曲阳县| 清水河县| 榆社县| 宣化县| 清镇市| 临泉县| 棋牌| 磐安县| 海伦市| 临漳县| 中西区| 凤翔县| 怀集县| 确山县| 扎鲁特旗| 龙胜| 高台县| 获嘉县| 古浪县| 沂南县| 深泽县| 巫山县| 琼中| 宜兴市| 小金县| 兴化市| 竹溪县|