为什么在以下带有defer的golang代码示例中得到0和1

时间:2019-05-02 10:37:29

标签: go deferred

以两种不同方式声明的变量的defer调用会产生不同的结果

Widget _reviewBody() {
    return SliverToBoxAdapter(
      child: Container(
        width: 10.0,
        padding: EdgeInsets.only(bottom: 30.0),
        child: TextField(
          onChanged: (text) {
            setState(() {
              reviewBody = text;
            });
          },
          keyboardType: TextInputType.multiline,
          maxLines: null,
          decoration: InputDecoration(
            hintText: 'Add your thoughts here',
            hintStyle: TextStyle(color: Burnt.hintTextColor),
            enabledBorder: UnderlineInputBorder(borderSide: BorderSide(color: Burnt.lightGrey)),
            focusedBorder: UnderlineInputBorder(borderSide: BorderSide(color: Burnt.primaryLight, width: 1.0)),
          ),
          textAlign: TextAlign.center,
        ),
      ),
    );
  }

https://play.golang.org/p/gfnnCZ--DkH

1 个答案:

答案 0 :(得分:7)

在第一个示例中,i是一个(传入)参数。在return语句中,计算返回值,然后执行延迟函数,然后递增i对返回值没有影响。

在第二个示例中,i是结果参数的名称。在return语句中,您明确返回值i,然后将其分配给返回值i(这是一个空操作)。但是,允许延迟函数修改返回“变量”的值,如果这样做,则会对实际返回的值产生影响。

如果我们再添加一个示例,这将变得更清楚:

func c2() (i int) {
    defer func() { i++ }()
    return 2
}

此函数将返回3,因为return 2语句会将2分配给i,然后推迟的函数将对此递增,因此返回值将为3。在Go Playground上尝试这个。 Spec: Return statements:

的相关部分
  

用于指定结果的“返回”语句在执行任何延迟函数之前会设置结果参数。

通常,如果函数(或方法)已命名结果参数,则返回值将始终是这些变量的值,但一定不要忘记return语句可能会向这些结果参数分配新值,并且可以通过return语句后的 延迟函数对其进行修改。

Spec: Defer statements中提到了这一点:

  

例如,如果延迟函数是function literal,而周围函数的named result parameters在文字范围内,则延迟函数可以在返回结果参数之前对其进行访问和修改。

博客文章Defer, Panic and Recover中也提到了该问题:

  

延迟的函数可以读取并分配给返回函数的命名返回值。

以及在Effective Go: Recover中:

  

如果doParse出现紧急情况,恢复块会将返回值设置为nil-延迟函数可以修改命名的返回值。

查看相关问题:How to return a value in a Go function that panics?