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

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

為什么需要default

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

  • 場景一
    在switch語句中,前面的case是特殊的處理,default分支里是默認(rèn)實現(xiàn)。在這種情況下,default分支恰好契合了default的語義。譬如:
void bar(WeekDay day) {
    switch (day)
        case SATURDAY: {
            //something
            break;
        }
        case SUNDAY: {
            //something else
            break;
        }
        default: {
            //working day, default case
            break;
        }
    }
}
  • 場景二
    利用default分支來捕獲設(shè)計中沒有考慮到的異常的值,譬如:
void foo(int type) {
    switch(type) {
        case 1: {
            //something
            break;
        }
        case 2: {
            //something else
            break;
        }
        default: {
            // unknown type!
            // error-handling
            break;
        }
    }
}
  • 場景三
    default分支里不需要做任何處理。default在這里提醒讀者,這種情況已經(jīng)考慮到了,只是沒有什么語句需要執(zhí)行。
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分支已經(jīng)窮舉了所有的可能,default分支引入的是一段永遠(yuǎn)不會被運行到的死代碼。每一行代碼讀增加了閱讀、維護的成本,良好的編程實踐一直要求我們盡量刪除死代碼。這種場景下default分支是否應(yīng)該刪除呢?考量下面兩個例子:

例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;
    }
}

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

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

不需要default的場景

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

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.

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

測試結(jié)果

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

Paste_Image.png

結(jié)論

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

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

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

友情鏈接更多精彩內(nèi)容