草庐IT

golang 推迟在预期时不评估

coder 2023-06-29 原文

因此,根据规范,延迟函数中的值在调用延迟函数时进行计算,但直到封闭函数返回时才会执行操作。我明白了,并且理解了整个“for i:=0;i<4;i++ defer="" example="" prints="">

但是,当我尝试使用 defer 临时分配覆盖值时(将最大 m 分配给队列长度 q),然后确保在我完成后重置该值(演示的示例已简化):

type tss struct {
    q int
    m int
}

func (t *tss) test() {
    if true {
        defer func() {
            t.q=t.q     //this should evaluate to 't.q = 50' right?
            fmt.Println("assigned",t.q,"to t.q")
        }()
        t.q = t.m
    }
    fmt.Printf("q=%v, m=%v\n", t.q, t.m)
}

func main() {
    ts := tss{50,1}
    fmt.Printf("q=%v, m=%v\n", ts.q, ts.m)
    ts.test()
    fmt.Printf("q=%v, m=%v\n", ts.q, ts.m)
}

我希望收到输出:

q=50, m=1
q=1, m=1
assigned 50 to t.q
q=50, m=1

但实际输出是:

q=50, m=1
q=1, m=1
assigned 1 to t.q
q=1, m=1

因此,似乎在错误的时间评估了这些值。但是,当我首先将 t.q 转储到一个变量中并将该赋值移到延迟函数之外,并将测试函数更改为如下所示时:

func (t *tss) test() {
    if true {
        qtmp := t.q
        defer func() {
            //assigning qtmp here still assigns 1 back to t.q
            t.q=qtmp
            fmt.Println("assigned",t.q,"to t.q")
        }()
        t.q = t.m
    }
    fmt.Printf("q=%v, m=%v\n", t.q, t.m)
}

我得到上面的预期输出,其中分配了 50。

我是不是遇到了错误,还是我遗漏了有关在延迟函数中赋值的内容?

可能需要注意的是,如果我将 t.q 作为函数参数传入,也同样有效:

func (t *tss) test() {
    if true {
        defer func(q int) {
            t.q=q
            fmt.Println("assigned",t.q,"to t.q")
        }(t.q)
        t.q = t.m
    }
    fmt.Printf("q=%v, m=%v\n", t.q, t.m)
}

编辑:这是使用答案中的方法的完整版本:

type tss struct {
    q int
    m int
}

func (t *tss) test() {
    if true {
        defer func(q int) {
            t.q=q     //this will correctly evaluate to 't.q = 50'
            fmt.Println("assigned",t.q,"to t.q")
        }(t.q)
        t.q = t.m
    }
    fmt.Printf("q=%v, m=%v\n", t.q, t.m)
}

func main() {
    ts := tss{50,1}
    fmt.Printf("q=%v, m=%v\n", ts.q, ts.m)
    ts.test()
    fmt.Printf("q=%v, m=%v\n", ts.q, ts.m)
}

和正确的输出:

q=50, m=1
q=1, m=1
assigned 50 to t.q
q=50, m=1

最佳答案

所以我在校对我的帖子时回答了我自己的问题。与其删除它以掩饰我的尴尬,不如将其保留以防其他人遇到同样的困惑。

延迟函数在调用时计算函数的任何 ARGUMENTS。它不会立即计算函数体内的任何值。因此,在延迟操作发生时执行内部分配。

所以:

  1. 代码运行
  2. 遇到延迟语句
  3. golang 存储参数值以备后用
  4. 延迟函数的主体被完全忽略
  5. 其余代码运行到封闭函数的末尾
  6. 使用存储的参数值执行延迟函数

-迈克

关于golang 推迟在预期时不评估,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/28459917/

有关golang 推迟在预期时不评估的更多相关文章

  1. ruby-on-rails - ruby 日期方程不返回预期的真值 - 2

    为什么以下不同?Time.now.end_of_day==Time.now.end_of_day-0.days#falseTime.now.end_of_day.to_s==Time.now.end_of_day-0.days.to_s#true 最佳答案 因为纳秒数不同:ruby-1.9.2-p180:014>(Time.now.end_of_day-0.days).nsec=>999999000ruby-1.9.2-p180:015>Time.now.end_of_day.nsec=>999999998

  2. ruby - 在 Ruby 中的另一个上下文中评估潜在的相对 URI - 2

    我在Ruby程序中有两个URI。一个肯定是绝对URI,另一个可能是绝对URI或相对URI。我想在第一个的上下文中将第二个转换为绝对URI,所以如果第一个是http://pupeno.com/blog第二个是/about,结果应该是http://pupeno.com/about.有什么想法吗? 最佳答案 Ruby的内置URI和Addressablegem,做这个简短的工作。我更喜欢Addressable,因为它功能更全面,但URI是内置的。require'uri'URI.join('http://pupeno.com/blog','/

  3. ruby - Sinatra session 未按预期持续 - 2

    我正在尝试使用Sinatra中的重定向和session在网站周围传递一些数据。这是一个简化的示例,使用PrettyPrint进行调试:require'pp'require'rubygems'require'sinatra'enable:sessionsget'/'dosession[:foo]='12345'puts'session1'ppsessionredirectto('/redir')endget'/redir'doputs'session2'ppsession'helloworld'end查看Thin的输出,我看到:>>Listeningon0.0.0.0:4567,CTRL

  4. ruby - 为什么 Minitest 的 assert_raises 在这种情况下没有按预期工作? - 2

    我正在尝试使用ActionControllerbugreporttemplate解决Rails中的一个奇怪行为.为了记录,这是模板中的Controller:classTestController我已经为缺失的Action添加了一条路线:routes.drawdoget'/'=>'test#index'get'/missing'=>'test#missing'end并且我试图断言AbstractController::ActionNotFound在遵循该路线时被引发:classBugTest预期行为:绿色测试。实际行为:#Runningtests:D,[2014-04-24T09:17:

  5. ruby - block 内的实例评估 - 2

    我有一个Builder类,可让您添加到其中一个实例变量:classBuilderdefinitialize@lines=[]enddeflinesblock_given??yield(self):@linesenddefadd_line(text)@lines现在,我该如何改变它my_builder=Builder.newmy_builder.lines{|b|b.add_line"foo"b.add_line"bar"}pmy_builder.lines#=>["foo","bar"]进入这个?my_builder=Builder.newmy_builder.lines{add_li

  6. ruby - 使用 autoload 与 ruby​​ 中的 require 进行惰性评估? - 2

    在我的代码中,我使用自动加载进行惰性评估,这样我可以更快地加载程序并在需要时加载文件,我没有看到很多人使用它,但在Thin项目中我注意到自动加载已被广泛使用,反正只是想知道使用它是否有任何风险。 最佳答案 autoload是notthreadsafe并将在未来的Ruby版本中弃用。这是proofbyMatz(ruby的创造者)。 关于ruby-使用autoload与ruby​​中的require进行惰性评估?,我们在StackOverflow上找到一个类似的问题:

  7. ruby - 如何预期失败的步骤并传递 cucumber 中的失败? - 2

    我们想测试cucumber的步骤定义。我们希望能够检查的一件事是我们期望失败的测试实际上失败了。为此,我们想编写我们知道会失败的场景并将它们添加到我们的测试套件中,但标记或以其他方式表示它们以便当且仅当它们失败时它们“通过”。如何解决这个问题? 最佳答案 您应该测试负面状态。失败的步骤只是通过步骤的倒数。所以做这样的事情:Then/ishouldnotbetrue/dosome_value.should_notbe_trueend这就是我进行失败测试的方式。您还可以捕获异常等,并验证block是否确实抛出该异常lambdadosom

  8. ruby - Sinatra json 渲染没有按预期工作 - 2

    我在Sinatra中遇到问题,我无法仅使用json进行响应,而且我在任何地方都找不到好的sinatra文档,大部分内容似乎都已过时。无论如何,这是代码:moduleMemcachedManagerclassApp我得到的回应是:"\n{\"hello\":\"world\"}\n"它应该只是json部分的地方。为什么它在我没有要求时呈现html标签? 最佳答案 你见过thisblogpost吗??require'json'get'/example.json'docontent_type:json{:key1=>'value1',:k

  9. ruby - 帮助评估构建工具 - 2

    我已经熟悉并使用Ant&Maven,此时我想扩展到另一个工具,我在“Buildr”和“Gradle”之间做出决定。我非常感谢那些使用过其中一种或两种工具的人的见解/反馈,因为坦率地说,在这一点上,对我来说唯一真正的区别似乎是ruby​​与groovy(我对两者都感到满意并喜欢)。我也希望能回答以下问题:我知道Buildr允许下载和提取不在maven类型存储库中的依赖项,Gradle是否提供相同的功能?Buildr/Gradle能否用于构建其他语言的源代码——即groovy、ruby、actionscript/flex、c系列等?Buildr/Gradle与Hudson或Jenkins的

  10. ruby-on-rails - Ruby 类评估,validates_inclusion_of 与动态数据 - 2

    如果我有如下的ActiveRecord模型classFooself.allowed_typesdefself.allowed_types#somecodethatreturnsanenumerableendend这不起作用,因为在评估验证时尚未定义allowed_types方法。我能想到的所有修复基本上都是围绕将方法定义移到验证之上,以便在需要时可用。我明白这可能更像是一个编码风格问题(我希望我的所有验证都在模型顶部,方法在底部)但我觉得应该有某种解决方案,可能涉及初始模型加载的惰性评估?我想做的事有可能吗?我应该只在验证之上定义方法,还是有更好的验证解决方案来实现我想要的。

随机推荐