2017-10-09 38 views
1

我知道這是推遲一個過程。我也讀過一些例子,比如在處理File和其他資源時很好用。我的問題是,這是不是在Python等其他語言處理?如果是,Go是如何提供一些獨特的功能?Go中的Deferred函數是如何有用以及在其他語言中可用的替代方法?

說,有兩個功能f1f2,我想打電話給f2f1完成。我可以這樣做:

def f1(): 
    done = False 
    print('I am doing extensive work') 
    done = True 
    return done 

def f2(): 
    print('here we go') 

if f1(): 
    f2() 

通過最小化編碼工作是推遲做同樣的事情?

回答

2

defer顧名思義,會延遲延遲函數的執行,直到調用函數體退出,不管退出點和條件如何。。因此,即使f1中的某些內容失敗併發生異常,您的功能f1確認f2將確保調用f2。我認爲它是來自try/catch塊的finally子句。

在Python中,我能想到的最接近的東西就是defer,它們是context managers。注意我怎麼說最接近和不相同,因爲他們的目的重疊了一點,但只有一點

1

去的defer statement只是另一種方法,它有其優點和缺點(不一定是最好的)。其他語言提供了處理適當資源關閉的替代方案。例如Java提供了異常和try-catch塊。

Go FAQ: Why does Go not have exceptions?

報價我們相信,耦合例外控制結構,如try-catch-finally成語,結果令人費解的代碼。它也傾向於鼓勵程序員標記太多的普通錯誤,例如無法打開文件,例外。

Go採取不同的方法。對於普通的錯誤處理,Go的多值返回可以輕鬆報告錯誤而不會重載返回值。 A canonical error type, coupled with Go's other features,使錯誤處理令人愉快,但與其他語言中的錯誤處理完全不同。

Go還有一些內置函數可用來發出信號並從真正的特殊條件中恢復。恢復機制僅作爲一個函數狀態在錯誤發生後被拆除的一部分來執行,這足以處理災難,但不需要額外的控制結構,並且如果使用得當,可以產生乾淨的錯誤處理代碼。

有關詳細信息,請參閱Defer, Panic, and Recover文章。

相比,Java的try-catch例如使用defer的優勢在於處理關閉或打開資源處置的代碼是旁邊打開它的代碼。

例如:

f, err := os.Open("file.txt") 
if err != nil { 
    log.Printf("Failed to open file: %v", err) 
    return 
} 
defer f.Close() 

// f is open you may read from it 
... 

如果在資源處置等語言被移動到另一個代碼塊,這是很難跟蹤在那裏,如果你真正把它配置的服務。

1

要理解延遲,您需要了解替代方法。

在複雜的代碼處理許多資源,你最終會做這樣的(僞代碼)的東西:

mtx.Lock() 
file1, err := os.Open(...) 
if err != nil { 
    mtx.Unlock() 
    return err 
} 
conn, err := net.Dial(...) 
if err != nil { 
    file1.Close() 
    mtx.Unlock() 
    return err 
} 
file2, err := os.Open(...) 
if err != nil { 
    conn.Close() 
    file1.Close() 
    mtx.Unlock() 
    return err 
} 
do_things() 
file2.Close() 
conn.Close() 
file1.Close() 
mtx.Unlock() 
return nil 

這得到詳細的快。而且,從長期來看,它很容易出錯,因爲有人編輯代碼,並可能在打開file1之前將網絡連接的開放移動到可能無法正確更新所有錯誤處理路徑。

在C,這裏常見的成語是收集資源的全部清理在函數的末尾,做這樣的事情:

ret = ERROR; 
    lock(mtx); 
    fd1 = open(...); 
    if (fd1 == -1) 
     goto err1; 
    conn = net_conn(...); 
    if (conn == -1) 
     goto err2; 
    fd2 = open(...); 
    if (fd2 == -1) 
     goto err3; 
    do_things(); 

    ret = 0; 
    close(fd2); 
err3: 
    close(conn); 
err2: 
    close(fd1); 
err1: 
    unlock(mtx); 
    return ret; 

這是不漂亮或者,它是很容易得到這個也是錯的。

作爲比較做同樣的事情有延遲,我們得到:

mtx.Lock() 
defer mtx.Unlock() 
file1, err := os.Open(...) 
if err != nil { 
    return err 
} 
defer file1.Close() 
conn, err := net.Dial(...) 
if err != nil { 
    return err 
} 
defer conn.Close() 
file2, err := os.Open(...) 
if err != nil { 
    return err 
} 
defer file2.Close() 
.... do things ... 
return nil 

很清晰,簡潔,誰知道去就會明白髮生了什麼,這是非常難拿錯或將來打破。

相關問題