不是每一個switch語句都需要一個default

不是每一個switch語句都需要一個default

為什么需要default

給每一個swith加上default分支,一直是一個推薦的實踐。在以下三種場景下都建議使用default分支。

  • 場景一
    在switch語句中,前面的case是特殊的處理,default分支里是默認實現。在這種情況下,default分支恰好契合了default的語義。譬如:
void bar(WeekDay day) {
    switch (day)
        case SATURDAY: {
            //something
            break;
        }
        case SUNDAY: {
            //something else
            break;
        }
        default: {
            //working day, default case
            break;
        }
    }
}
  • 場景二
    利用default分支來捕獲設計中沒有考慮到的異常的值,譬如:
void foo(int type) {
    switch(type) {
        case 1: {
            //something
            break;
        }
        case 2: {
            //something else
            break;
        }
        default: {
            // unknown type!
            // error-handling
            break;
        }
    }
}
  • 場景三
    default分支里不需要做任何處理。default在這里提醒讀者,這種情況已經考慮到了,只是沒有什么語句需要執行。
switch(keystroke) {
    case 'w': {
        // move up
        break;
    }
    case 'a': {
        // move left
        break;
    }
    case 's': {
        // move down
        break;
    }
    case 'd': {
        // move right
        break;
    }
    default: {
        //nothing
        break;
    }
}

default分支引入dead code

而在某些場景下case分支已經窮舉了所有的可能,default分支引入的是一段永遠不會被運行到的死代碼。每一行代碼讀增加了閱讀、維護的成本,良好的編程實踐一直要求我們盡量刪除死代碼。這種場景下default分支是否應該刪除呢?考量下面兩個例子:

例1

int flag = value > 1000 ? 1 : 0;
switch(flag) {
    case 0: {
        //something
        break;
    }
    case 1: {
        //something else
        break;
    }
    default: {
        //for sanity, never reach here
        break;
    }
}

可以很容易地發現default分支永遠不會被執行。default分支的唯一作用類似于注釋,表示前面的case確實已經窮舉了所有的可能。在這種情況下是否定義default分支,取決于強迫癥的嚴重程度,加或是不加沒有太大分別,關鍵在于制訂統一的規則然后嚴格地執行。

例 2

enum Colour {
    RED,
    WHITE
};
void test(const Colour& colour) {
    switch(colour) {
        case RED: {
            //something
            break;
        }
        case WHITE: {
            //something else
            break;
        }
        default: {
            //nothing
            break;
        }
    }
}

這個例子里,default分支里邏輯是不是死代碼呢?目前看是的,但當某一天Colour的定義發生了變化增加了其他定義,default里的邏輯就不再是死代碼。
這個例子可以歸為場景2,利用default分支來捕獲設計中沒有考慮到的異常的值。在default分支中增加錯誤處理邏輯,一旦進入該分支就說明出現了意料之外的值,需要對程序做修復。

不需要default的場景

至此,我們都在討論為什么需要default,那么什么時候不需要default呢?參考某司的編程規范:

Avoid default case (but set a default value before switch/case) for switch/case on all values of an enum (N/A if not on all values) to detect missing cases by compilation.

這條規范要表達的意思是,如果switch里的變量類型是枚舉類型,不要加default分支。如果漏掉了針對某個枚舉值的分支,在沒有default分支的情況下,會有編譯告警。

測試結果

mac os + clangLinux + gcc的環境下,如果定義了default分支,編譯通過。如果不定義default分支,會產生編譯告警。

Paste_Image.png

結論

在使用枚舉值作為switch的參數時,如果漏掉了對某個值的處理,不加default 分支時會產生編譯告警,可以快速發現潛在的問題。而定義default分支并在default分支中添加錯誤處理的方式,需要在運行時才有可能發現錯誤。只有當用漏掉處理的值作為參數來觸發switch邏輯時問題才會暴露。
基于此,建議在使用枚舉值作為switch的參數,并且需要窮舉所有枚舉值時不要定義default分支。

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。

推薦閱讀更多精彩內容

  • 53.計算字符 在字符串中獲取字符值的數量, 可以使用字符串字符屬性中的計數屬性: let unusualMena...
    無灃閱讀 1,140評論 0 4
  • title: "Swift 中枚舉高級用法及實踐"date: 2015-11-20tags: [APPVENTUR...
    guoshengboy閱讀 2,624評論 0 2
  • Swift提供了多種控制流聲明。包括while循環來多次執行一個任務;if,guard和switch聲明來根據確定...
    BoomLee閱讀 2,002評論 0 3
  • 86.復合 Cases 共享相同代碼塊的多個switch 分支 分支可以合并, 寫在分支后用逗號分開。如果任何模式...
    無灃閱讀 1,444評論 1 5
  • 離職后回家了,回家第一天,有很多的不適應感,雖然這是自己的家,但是依然感覺很陌生,害怕與家人發生矛盾,害怕自己不適...
    暗黑系少女閱讀 205評論 0 0