Go语言中的静态局部变量

43

在 Go 中,是否可以定义一个本地变量,使其能够在一个函数调用和另一个函数调用之间保持其值?在 C 中,我们可以使用保留字 static 来实现这一点。

C 语言示例:

int func() {
    static int x = 0; 
    x++;
    return x;
}

很好的问题。我在想为什么Go语言没有实现这个功能。由于Go语言中的每个东西都经过了精心挑选,因此不实现静态变量一定有一个很好的理由。 - M.E.
7个回答

38

使用闭包

函数字面量是闭包:它们可以引用在周围函数中定义的变量。这些变量随后在周围函数和函数字面量之间共享,并且只要它们可访问,它们就会一直存在。

它不必在全局范围内,只需在函数定义外部即可。

func main() {

    x := 1

    y := func() {
        fmt.Println("x:", x)
        x++
    }

    for i := 0; i < 10; i++ {
        y()
    }
}

(在Go Playground上的示例)


假设我有一个变量在文件顶部(任何方法外),它会被所有函数访问吗?在go playground上是这样的。 - filthy_wizard
2
遗憾的是,该函数在主函数之外,所以这种模式对我不起作用。 - Jesse Chisholm
6
不确定我们是否真的可以将这种用法与静态相比较。 这更像是一个全局变量... x对于func来说是全局变量。 - Amit

23

你可以像这样做

package main

import (
    "fmt"
)

func main() {
  f := do()
  f() // 1
  f() // 2
}

func do() (f func()){
  var i int
  f = func(){
    i++
    fmt.Println(i)
  }
  return
}

玩耍链接 https://play.golang.org/p/D9mv9_qKmN


3
+1 是因为它既是线程安全的(不像 mjibson 的答案),又可以对使用持久化变量的函数进行单独的单元测试(不像 IamNaN 所接受的答案)。 - Lost Crotchet
有趣。我的第一感觉是C语言的静态变量要简单得多,但实际上我认为这更加通用和优雅。 - hmijail
1
@LostCrotchet 如果这比全局变量更线程安全,我会非常惊讶。两个线程可以同时调用f(),这应该会引起问题。两个线程可以通过do()实例化自己的函数,然后调用它们将是线程安全的,因为它们操作不同的资源。但是,这个问题显然可以用更简单的方法解决。这里的问题是创建一个始终在相同一组资源上运行的单个函数,这肯定从定义上来说是不可能线程安全的。不过,你提到的单元测试也很有道理。 - Alexander Guyer
同意@AlexanderGuyer的观点,这种方式无法保证线程安全。 - R. van Twisk

20

在全局范围内声明一个变量:

var i = 1

func a() {
  println(i)
  i++
}

4

使用函数闭包

在下面的例子中,变量sum对于每个闭包a1和a2都像是一个单独的静态变量。

package main

import "fmt"

func adder() func(int) int {
    sum := 0
    return func(x int) int {
        sum += x
        return sum
    }
}

func main() {
    a1,a2 := adder(), adder()
    for i := 0; i < 10; i++ {
        fmt.Println(
            a1(i),
            a2(-1*i),
        )
    }
}

输出

0 0
1 -1
3 -3
6 -6
10 -10
15 -15
21 -21
28 -28
36 -36
45 -45

3

像Taric的建议一样,但是staticCounter()返回一个int函数

package main

import (
    "fmt"
)

func staticCounter() (f func()(int)){
  var i int
  f = func()(int){
    i++
//  fmt.Println(i)
    return i
  }
  return
}

func main() {
  f := staticCounter()
  g := staticCounter()
  fmt.Println(f())
  fmt.Println(f())
  fmt.Println(f())
  fmt.Println(f())
  fmt.Println(g())
  fmt.Println(g())
}

1
在其他所有答案中,包含静态变量的函数是在主函数中分配的。
以下是如何在全局范围内定义和分配该函数。
var myFunction = func() func(type1, type2) type3 {
    myStaticVariable := []string {"hello", "world"}
    return func(arg1 type1, arg2 type2) type3 {
        // use arg1, arg2 and myStaticVariable here
    }
}()

0
// A var x1 is local to main(), is not a global var.
// A static var is one that can't be accesed from others functions just
// like global vars.
// A static var dont disappears when the function ends.
// So is what x1 n x2 are pretending in this program.
package main

import (
    "fmt"
)

/*
int func() {     // x static inside a function.
    static int x = 0;
    x++;
    return x;
}
*/

// 

func main() {

    //
    var x1 int = 0
    var x2 int = 100
    //

    for i := 0; i < 10; i++ {           // call to a "static" var x

        x1 = fun1(&x1)
        x2 = fun2(&x2)

        fmt.Printf("%d     %d \n", x1, x2)

    } //

    test1(x1, x2) // a funct needs parameters to see x1 n x2

} //main

//

func fun1(p *int) int {
    //
    *p++ // save value

    return *p //counter  x1
}

//

func fun2(p *int) int {

    *p++      // save value
    return *p //counter x2
}

//

func test1(x1 int, x2 int) {
    fmt.Println("\"x1\" y \"x2\"  ", x1, x2)
}

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接