源码包里的一个用法的小疑惑

 func (db *DB) exec(query string, args []interface{}) (res Result, err error) {
  dc, err := db.conn()
  if err != nil {
    return nil, err
  }
  defer func() {        这里直接写 defer db.putConn(dc, err) 不行吗?这样写有什么意义?
    db.putConn(dc, err)
  }()           

  if execer, ok := dc.ci.(driver.Execer); ok {
    dargs, err := driverArgs(nil, args)
    if err != nil {
      return nil, err
    }
    dc.Lock()
    resi, err := execer.Exec(query, dargs)
    dc.Unlock()
    if err != driver.ErrSkip {
      if err != nil {
        return nil, err
      }
      return driverResult{dc, resi}, nil
    }
  }

  dc.Lock()
  si, err := dc.ci.Prepare(query)
  dc.Unlock()
  if err != nil {
    return nil, err
  }
  defer withLock(dc, func() { si.Close() })
  return resultFromStatement(driverStmt{dc, si}, args...)
}

共 4 个回复


stevewang

直接写defer db.putConn(dc, err)不行,因为这时候参数的值已经确定了。如果是源代码里的写法,putConn的参数就是exec函数返回前的实际值。

# 0

snake117

1楼说的不错是的。

# 1

16779242

1楼说的对。

给个简单的例子楼主可以尝试一下:

func main() {
    i := 10
    defer fmt.Println(i)
    i++
}

输出结果是10

func main() {
    i := 10
    defer func() {
        fmt.Println(i)
    }()
    i++
}

输出结果就是11了

# 2

shaovie

原来如此啊,我还以为只是记下这个表达式,最后再执行呢,没想到把当前的变量也记下来了

# 3