为了账号安全,请及时绑定邮箱和手机立即绑定

延迟函数执行顺序

延迟函数执行顺序

Go
守着星空守着你 2022-10-10 17:55:00
我正在学习 golang 源代码并陷入延迟函数执行顺序。我有两个文件:一个定义端点的行为,另一个用于测试。我删除了一些与我的问题无关的代码以减少阅读的行数。端点定义文件// Endpoint is the fundamental building block of servers and clients.// It represents a single RPC method.type Endpoint func(ctx context.Context, request interface{}) (response interface{}, err error)// Middleware is a chainable behavior modifier for endpoints.type Middleware func(Endpoint) Endpoint// Chain is a helper function for composing middlewares. Requests will// traverse them in the order they're declared. That is, the first middleware// is treated as the outermost middleware.func Chain(outer Middleware, others ...Middleware) Middleware {    return func(next Endpoint) Endpoint {        for i := len(others) - 1; i >= 0; i-- { // reverse            next = others[i](next)        }        return outer(next)    }}测试文件包含打印的步骤。func ExampleChain() {    e := endpoint.Chain(        annotate("first"),        annotate("second"),        annotate("third"),    )(myEndpoint)    if _, err := e(ctx, req); err != nil {        panic(err)    }    // Output:    // first pre    // second pre    // third pre    // my endpoint!    // third post    // second post    // first post}var (    ctx = context.Background()    req = struct{}{})据我了解,这三个annotate方法应该先执行,然后endpoint.Chain方法,myEndpoint最后执行。此外,由于pre首先打印,并且当函数返回“post”时,应该按照defergo doc 中的说明进行操作: A "defer" statement invokes a function whose execution is deferred to the moment the surrounding function returns, either because the surrounding function executed a return statement, reached the end of its function body, or because the corresponding goroutine is panicking.所以我期望看到的是    // Output:    // first pre    // first post    // second pre    // second post    // third pre    // third post    // my endpoint!简而言之,我的问题是:为什么first pre后面不跟first post,一样second third。s的顺序post颠倒了。endpoint.Chain反向执行返回值列表但annotate首先annotate评估方法对吗?不是说,pres 被打印,这意味着首先执行内部函数
查看完整描述

2 回答

?
小怪兽爱吃肉

TA贡献1852条经验 获得超1个赞

延迟函数作为函数中的最后一件事运行,在 return 语句之后,所以annotate函数将首先运行next,只有在返回之后,延迟函数才会运行。根据您的代码,它应该打印的顺序是:


first pre

second pre

third pre

my endpoint

third post

second post

first post


查看完整回答
反对 回复 2022-10-10
?
阿晨1998

TA贡献2037条经验 获得超6个赞

这是您的示例变成了在 Go 操场上运行的东西。

请注意,如果您在给定函数中defer 多次调用,则每个延迟调用都按 LIFO 顺序运行。因此,如果您想使用defer确保您post首先被调用,然后是next操作,请考虑替换:


defer fmt.Println(s, "post")

next(ctx, request)

和:


defer next(ctx, request)

defer fmt.Println(s, "post)

当然,在您的情况下,您想返回什么next返回,这会产生一个小问题。要在实际情况下解决这个问题,您需要一个小函数和一些命名的返回值:


defer func() { i, e = next(ctx, request) }()

其中i和e是命名的返回值。


这是相同的代码变成了一个新示例,其中延迟调用以所需的顺序发生。 在这种情况下,这个例子是相当愚蠢的,因为没有任何恐慌,也没有中间的“危险步骤”,所以我们真正需要的是fmt.Println按顺序执行这两个调用,而不使用defer. 但是,如果我们可以在the和 post 部分之间感到恐慌fmt.Println(s, "pre"),那么这可能是有道理的。



查看完整回答
反对 回复 2022-10-10
  • 2 回答
  • 0 关注
  • 75 浏览
慕课专栏
更多

添加回答

举报

0/150
提交
取消
意见反馈 帮助中心 APP下载
官方微信