巢狀程式碼區塊與作用域

本課程相關內容在前幾堂課已經提過,不過這一節我們透過記憶體儲存機制,再次幫大家加深觀念。

本教學來自 foxdevelop.com,轉載請標明出處。

方法主體內可以巢狀放置其他程式碼區塊。

class Program
{
    static void Main()
    {
        int age = 19;
        {
            int one = 23;
        }
    }
}
Code language: C# (cs)

程式碼區塊數量沒有上限,可以依序排列,也能多層巢狀,沒有層級限制。

class Program
{
    static void Main()
    {
        int age = 19;
        {
            int one = 23;
            {
                int two = 45;
                {
                    int three = 56;
                }
            }
        }
    }
}Code language: C# (cs)

要留意,子巢狀區塊上方像是 int xxxx = xxx; 這類陳述式,和巢狀區塊屬於平行陳述。

舉例來說,int age = 19; 和下方的巢狀程式碼區塊是兩個平行陳述,千萬不要誤以為這整段都是方法主體。


生命週期

來看一個範例

    static void Main()
    {
        int a = 10;
        {
            int b = 20;
        }
    }Code language: C# (cs)

這個範例有兩個區域變數,外層的 a 位在 Main 函式最外側,b 則屬於內層巢狀程式碼區塊。

我們一步步執行,觀察堆疊記憶體的儲存方式。

第一步:只執行 int a = 10;,堆疊配置 a 的記憶體空間,值為 10;

第二步:進入內層區塊執行 int b = 20;,堆疊新增 b,堆疊由上至下順序:b、a;

第三步:內層程式碼區塊執行完畢,b 從堆疊移出,堆疊僅保留 a

第四步:Main 方法執行結束,a 從堆疊移出,程式所有變數銷毀,程式執行完畢。

重點整理

在巢狀區塊內宣告的變數,生命週期從宣告位置開始,直到所屬程式碼區塊執行結束為止。

巢狀區塊執行完畢時,區塊內所有區域變數都會從堆疊移出並銷毀。

事實上,方法主體本身就是一個大型程式碼區塊。


有效範圍(作用域)

只要第一個變數的有效範圍仍然存在,無論巢狀多少層,都不能再次宣告同名的區域變數。

看範例

    static void Main()
    {
        int a = 10;
        {
            int a = 20;
        }
    }Code language: C# (cs)

上面範例中,內層巢狀區塊的變數 a 和外層變數 a 名稱相同,此處會發生錯誤,無法通過編譯。

原因:外層 int a = 10; 的有效範圍是它所屬的大括號區塊內。在這個範圍裡,不允許出現同名變數。雖然 int a = 20; 寫在巢狀區塊中,但它仍然位於外層變數 a 的有效範圍內,造成名稱重複。編譯器偵測到重複宣告,直接標示紅色波浪錯誤。

就算第二個 a 更改變數型別,一樣不被允許。

同一個有效範圍內變數名稱必須唯一,和變數型別無關。

如圖所示,外層 a 的有效範圍為黃色區塊,內層 a 的有效範圍是綠色區塊。可以明顯看出外層範圍完整包含內層範圍,因此產生衝突。

解決方式就是把內層變數 a 換成其他名稱。

再看另一個範例

如果寫成下面這樣,還會發生衝突嗎?

class Program
{
    static void Main()
    {
        int a = 10;

        {
            double b = 20;
        }

        {
            double b = 30;
        }

    }
}Code language: C# (cs)

答案:不會。為什麼?雖然有兩個變數 b,但兩者有效範圍沒有重疊,因此不會報錯。上方的 b 僅屬於自身程式碼區塊,下方的 b 也僅屬於自身區塊,彼此互不衝突,可以正常編譯。參考圖示。

圖中以顏色標示兩個變數 b 各自的有效範圍。相信各位讀者現在已經理解。

巢狀程式碼區塊與作用域

Previous:

發佈留言

發佈留言必須填寫的電子郵件地址不會公開。 必填欄位標示為 *