如何在Go语言中实现静态局部变量?

huangapple go评论111阅读模式
英文:

How to implement static local variable in go

问题

我正在学习使用Go语言。我想要实现一个静态局部变量,以避免声明一个全局变量。但是我在闭包方面遇到了困难。我希望只在第一次调用函数时打印一条消息,而不是每次都打印。

以下是我的代码:

  1. func append(path string, vars Vars) {
  2. // 只发出一次警告
  3. func() (func()){
  4. var f bool
  5. return func(){
  6. if len(vars["hostlurl"]) == 0 && !f {
  7. f = true
  8. fmt.Println("Warning: missing hosturl.")
  9. }
  10. }
  11. }()
  12. // 追加操作
  13. ...
  14. }

在这段代码中,局部代码if len(...从未被调用。

有没有办法避免添加全局变量?

谢谢你的帮助。

英文:

I'm in the learning curve with go. I like like 如何在Go语言中实现静态局部变量?

Well, I would like to implement such a static local variable to avoid to declare a global one. But I struggle with closure. I would like to print a message only the first time the function is called, and not the other times.

Here is my code

  1. func append(path string, vars Vars) {
  2. // raise a warning only once
  3. func() (func()){
  4. var f bool
  5. return func(){
  6. if len(vars["hostlurl"]) == 0 && !f {
  7. f = true
  8. fmt.Println("Warning: missing hosturl.")
  9. }
  10. }
  11. }()
  12. // append
  13. ...
  14. }

In this code the local code if len(... is never called

Is there a way to avoid to add a global variable?

Thank you for your help

答案1

得分: 4

在Go语言中,没有"静态局部变量"的概念。

如果一个函数需要状态,你有多种选择。可以在Go Playground上尝试以下所有选项。

可以使用包级别的变量:

  1. var state bool
  2. func f1() {
  3. if !state {
  4. state = true
  5. fmt.Println("f1() first")
  6. }
  7. fmt.Println("f1() called")
  8. }

测试:

  1. f1()
  2. f1()
  3. // 输出
  4. f1() first
  5. f1() called
  6. f1() called

或者将状态(指针)作为参数传递:

  1. func f2(state *bool) {
  2. if !*state {
  3. *state = true
  4. fmt.Println("f2() first")
  5. }
  6. fmt.Println("f2() called")
  7. }

测试:

  1. var state bool
  2. f2(&state)
  3. f2(&state)
  4. // 输出
  5. f2() first
  6. f2() called
  7. f2() called

或者可以使用方法,状态可以存储在接收器中:

  1. type foo struct {
  2. state bool
  3. }
  4. func (v *foo) f3() {
  5. if !v.state {
  6. v.state = true
  7. fmt.Println("foo.f3() first")
  8. }
  9. fmt.Println("foo.f3() called")
  10. }

测试:

  1. v := foo{}
  2. v.f3()
  3. v.f3()
  4. // 输出
  5. foo.f3() first
  6. foo.f3() called
  7. foo.f3() called

或者使用sync.Once,它也是并发安全的:

  1. var f2Once sync.Once
  2. func f4() {
  3. f2Once.Do(func() {
  4. fmt.Println("f4() first")
  5. })
  6. fmt.Println("f4() called")
  7. }

测试:

  1. f4()
  2. f4()
  3. // 输出
  4. f4() first
  5. f4() called
  6. f4() called

或者返回一个引用局部变量的闭包:

  1. func f5() func() {
  2. var state bool
  3. return func() {
  4. if !state {
  5. state = true
  6. fmt.Println("f5() first")
  7. }
  8. fmt.Println("f5() called")
  9. }
  10. }

测试:

  1. fret := f5()
  2. fret()
  3. fret()
  4. // 输出
  5. f5() first
  6. f5() called
  7. f5() called

也可以使用函数变量,将闭包赋值给它:

  1. var f6 = func() func() {
  2. var state bool
  3. return func() {
  4. if !state {
  5. state = true
  6. fmt.Println("f6() first")
  7. }
  8. fmt.Println("f6() called")
  9. }
  10. }()

测试:

  1. f6()
  2. f6()
  3. // 输出
  4. f6() first
  5. f6() called
  6. f6() called

还可以将方法值用作函数:

  1. type bar struct {
  2. state bool
  3. }
  4. func (v *bar) f7() {
  5. if !v.state {
  6. v.state = true
  7. fmt.Println("foo.f7() first")
  8. }
  9. fmt.Println("foo.f7() called")
  10. }
  11. var f7 = (&bar{}).f7

测试:

  1. f7()
  2. f7()
  3. // 输出
  4. f7() first
  5. f7() called
  6. f7() called
英文:

There are no "static local variables" in Go.

If a function needs a state, you have numerous options. Try all on the Go Playground.

You may use a package level variable:

  1. var state bool
  2. func f1() {
  3. if !state {
  4. state = true
  5. fmt.Println("f1() first")
  6. }
  7. fmt.Println("f1() called")
  8. }

Testing:

  1. f1()
  2. f1()
  3. // Output
  4. f1() first
  5. f1() called
  6. f1() called

Or pass the (pointer to) state as an argument:

  1. func f2(state *bool) {
  2. if !*state {
  3. *state = true
  4. fmt.Println("f2() first")
  5. }
  6. fmt.Println("f2() called")
  7. }

Testing:

  1. var state bool
  2. f2(&state)
  3. f2(&state)
  4. // Output
  5. f2() first
  6. f2() called
  7. f2() called

Or you may use a method and the state may be stored in the receiver:

  1. type foo struct {
  2. state bool
  3. }
  4. func (v *foo) f3() {
  5. if !v.state {
  6. v.state = true
  7. fmt.Println("foo.f3() first")
  8. }
  9. fmt.Println("foo.f3() called")
  10. }

Testing:

  1. v := foo{}
  2. v.f3()
  3. v.f3()
  4. // Output
  5. foo.f3() first
  6. foo.f3() called
  7. foo.f3() called

Or use sync.Once which is also concurrency safe:

  1. var f2Once sync.Once
  2. func f4() {
  3. f2Once.Do(func() {
  4. fmt.Println("f4() first")
  5. })
  6. fmt.Println("f4() called")
  7. }

Testing:

  1. f4()
  2. f4()
  3. // Output
  4. f4() first
  5. f4() called
  6. f4() called

Or return a closure that refers to a local variable:

  1. func f5() func() {
  2. var state bool
  3. return func() {
  4. if !state {
  5. state = true
  6. fmt.Println("f5() first")
  7. }
  8. fmt.Println("f5() called")
  9. }
  10. }

Testing:

  1. fret := f5()
  2. fret()
  3. fret()
  4. // Output
  5. f5() first
  6. f5() called
  7. f5() called

You may also use a function variable, assigning a closure to it:

  1. var f6 = func() func() {
  2. var state bool
  3. return func() {
  4. if !state {
  5. state = true
  6. fmt.Println("f6() first")
  7. }
  8. fmt.Println("f6() called")
  9. }
  10. }()

Testing:

  1. f6()
  2. f6()
  3. // Output
  4. f6() first
  5. f6() called
  6. f6() called

You may also use a method value as a function:

  1. type bar struct {
  2. state bool
  3. }
  4. func (v *bar) f7() {
  5. if !v.state {
  6. v.state = true
  7. fmt.Println("foo.f7() first")
  8. }
  9. fmt.Println("foo.f7() called")
  10. }
  11. var f7 = (&bar{}).f7

Testing:

  1. f7()
  2. f7()
  3. // Output
  4. f7() first
  5. f7() called
  6. f7() called

huangapple
  • 本文由 发表于 2022年5月4日 13:47:30
  • 转载请务必保留本文链接:https://go.coder-hub.com/72108438.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定