第十七章 不常見的流程控制程式結冓
Unusual Control Structures
17.1 常式的多重回傳
Multiple Returns from a Routine
在任何時候離開常式的方法。
return可以提高可讀性的時候
- 獲得解答,要立即回傳
- 不返回就得寫更多的程式碼跳過別的程式碼
if (A is true)
if (B is true)
if (C is true)
//...
不如改成
if (A isn't true)
return notA;
if (B isn't true)
return notB;
if (C isn't true)
return notC;
//...everything is right
簡潔。但是,在產品代碼中,還須要更多的程式碼來處理這些not的狀況。if (A isn't true)
{
status = Error_A;
return notA;
}
if (B isn't true)
{
status = Error_B;
return notB;
}
if (C isn't true)
{
status = Error_C;
return notC;
}
//...everything is right
更可以讓有相關性的陳述式在一起(Scop縮小),提高可維護性和可讀性。將每個常式的return數量降低
- 在增加可讀性時增加數量
- 在降低可讀性時降低數量
17.2 遞迴
Recursion
可產生優雅的解決方法,就用遞迴
用於小問題,產生簡單、正確的解決方案
遞迴使用心得
Tips for Using Recursion
留一個非遞迴的路徑,當作停止遞迴的出口
防止無限遞迴,考慮使用安全計數器,預防堆疊溢位
多常式遞迴,很危險,請保持在單一常式
使用new創造物件,不要讓它是auto創造出來。
不要使用遞迴運算階乘和數列的問題
17.3 goto()語法
goto
反對goto的論點
The Argument Against gotos
- 含有goto的程式碼沒有品質
- 邏輯結構無法利用排版凸顯
- 編譯器無法最佳化
支持goto的論點
The Argument for gotos
- goto使程式碼更快或更小
- 減少重覆的程式碼
關於goto的假辨論
The Phony goto Debate
結論:即使明白所有可以避開goto的程式技巧,但有時候使用goto卻可以提高可讀性和可維護性
goto與錯誤處理時
Error Processing and gotos
goto版
errorState = FileStatus_Success
fileIndex = 0
While ( fileIndex < numFilesToPurge ) And ( errorState = FileStatus_Success )
fileIndex = fileIndex + 1
If Not ( FindFile( fileList( fileIndex ), fileToPurge ) )
Then
errorState = FileStatus_FileFindError
GoTo END_PROC
End If
If Not OpenFile( fileToPurge )
Then
errorState = FileStatus_FileOpenError
GoTo END_PROC
End If
If Not OverwriteFile( fileToPurge )
Then
errorState = FileStatus_FileOverwriteError
GoTo END_PROC
End If
If Erase( fileToPurge )
Then
errorState = FileStatus_FileEraseError
GoTo END_PROC
End If
End While
DeletePurgeFileList( fileList, numFilesToPurge )
深巢狀if版
errorState = FileStatus_Success
fileIndex = 0
While ( fileIndex < numFilesToPurge ) And ( errorState = FileStatus_Success )
fileIndex = fileIndex + 1
If FindFile( fileList( fileIndex ), fileToPurge )
Then
If OpenFile( fileToPurge )
Then
If OverwriteFile( fileToPurge )
Then
If Not Erase( fileToPurge )
Then
errorState = FileStatus_FileEraseError
End If
Else ' couldn\'t overwrite file'
errorState = FileStatus_FileOverwriteError
End If
Else ' couldn\'t open file'
errorState = FileStatus_FileOpenError
End If
Else ' couldn\'t find file'
errorState = FileStatus_FileFindError
End If
End While
DeletePurgeFileList( fileList, numFilesToPurge )
Status變數版
errorState = FileStatus_Success
fileIndex = 0
While ( fileIndex < numFilesToPurge ) And ( errorState = FileStatus_Success )
fileIndex = fileIndex + 1
If Not FindFile( fileList( fileIndex ), fileToPurge )
Then
errorState = FileStatus_FileFindError
End If
If ( errorState = FileStatus_Success )
Then
If Not OpenFile( fileToPurge )
Then
errorState = FileStatus_FileOpenError
End If
End If
If ( errorState = FileStatus_Success )
Then
If Not OverwriteFile( fileToPurge )
Then
errorState = FileStatus_FileOverwriteError
End If
End If
If ( errorState = FileStatus_Success )
Then
If Not Erase( fileToPurge ) Then
errorState = FileStatus_FileEraseError
End If
End If
End While
DeletePurgeFileList( fileList, numFilesToPurge )
try-finally版
Try
fileIndex = 0
While ( fileIndex < numFilesToPurge )
fileIndex = fileIndex + 1
FindFile( fileList( fileIndex ), fileToPurge )
OpenFile( fileToPurge )
OverwriteFile( fileToPurge )
Erase( fileToPurge )
Wend
Finally
DeletePurgeFileList( fileList, numFilesToPurge )
End Try
寫法 | goto版 | 深巢狀if版 | 狀態變數版 | try-finally版 |
goto語法 | 可避開 | 可避開 | 可避開 | |
巢狀if的語法 | 可避開 | 可避開 | 可避開 | |
其它 | 避開額外測試 | 產生複雜的程式碼 | 需加入額外測試 | 並不是每個語言都支援 |
goto與共享在else裡的代碼
gotos and Sharing Code in an else Clause
goto版
if ( statusOk ) {
if ( dataAvailable ) {
importantVariable = x;
goto MID_LOOP;
}
}
else {
importantVariable = GetValue();
MID_LOOP:
// lots of code
...
}
呼叫常式版
if ( statusOk )
{
if ( dataAvailable )
{
importantVariable = x;
DoLotsOfCode( importantVariable );
}
}
else
{
importantVariable = GetValue();
DoLotsOfCode( importantVariable );
}
重建條件式版
if ( ( statusOk && dataAvailable ) || !statusOk )
{
if ( statusOk && dataAvailable )
{
importantVariable = x;
}
else
{
importantVariable = GetValue();
}
// lots of code
...
}
goto的使用原則和心得
Summary of Guidelines for Using gotos
goto的使用與否取決於信仰。
goto()代表效率。
沒有留言:
張貼留言
(什麼是留言欄訊息?)