什么时候应该初始化一个新变量,什么时候不应该?

时间:2014-07-02 20:09:25

标签: performance go

我正在查看代码示例sql.query,我对变量的初始化方式感到有些困惑。据我所知,var关键字初始化变量,但如果你已经有了这样的变量,最好“重用”它而不是重新初始化它。我知道我可能误解了golang规范,所以我希望这个问题可以帮助我(也许还有其他人)做对。

  rows, err := db.Query("SELECT name FROM users WHERE age=?", age)
    if err != nil {
            log.Fatal(err)
    }
    defer rows.Close()
    for rows.Next() {
            var name string
            if err := rows.Scan(&name); err != nil {
                    log.Fatal(err)
            }
            fmt.Printf("%s is %d\n", name, age)
    }
    if err := rows.Err(); err != nil {
            log.Fatal(err)
    }

为什么“name”变量在循环内初始化而不在循环之外? (见下文)。在每个循环中重新初始化它的性能不是很低吗?

//how I would do this
  rows, err := db.Query("SELECT name FROM users WHERE age=?", age)
    if err != nil {
            log.Fatal(err)
    }
    defer rows.Close()
    var name string //outside the loop
    for rows.Next() {

            if err := rows.Scan(&name); err != nil {
                    log.Fatal(err)
            }
            fmt.Printf("%s is %d\n", name, age)
    }
    if err := rows.Err(); err != nil {
            log.Fatal(err)
    }

甚至更好地使用指针

      rows, err := db.Query("SELECT name FROM users WHERE age=?", age)
        if err != nil {
                log.Fatal(err)
        }
        defer rows.Close()
        name := new(string) //pointer outside the loop
        for rows.Next() {

                if err := rows.Scan(name); err != nil {
                        log.Fatal(err)
                }
                fmt.Printf("%s is %d\n", name, age)
        }
        if err := rows.Err(); err != nil {
                log.Fatal(err)
        }

1 个答案:

答案 0 :(得分:3)

除非您已确定分配是性能瓶颈,否则我不会考虑这样的过早优化。毕竟,它甚至可能没有什么区别,所以最好在可读性/可维护性方面犯错误。

一般来说,我建议使用最小范围的变量,这是有意义的。如果它们是堆栈分配的,那么它们将非常便宜 - 假设空间可用,它可能只涉及将变量初始化为零或其初始值。在循环中作用的堆栈分配变量也可能每次都通过循环结束相同的内存位置,因此移出它们并没有太大的收获。

话虽如此,当在堆栈上分配变量时,它并不总是显而易见的。如果编译器决定传递给row.Scan的指针可能会在函数调用之后保留(即转义),那么name将在堆上分配虽然它已经用var定义。

同样,如果转义分析确定变量没有转义,则使用new创建字符串变量的版本可能会决定将其放在堆栈上。