2017-10-09 80 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 

很清晰,简洁,谁知道去就会明白发生了什么,这是非常难拿错或将来打破。

相关问题