当前位置: 首页 > 工具软件 > kLoop > 使用案例 >

GO loop variable captured by func literal

姬翰林
2023-12-01

defer中出现的例子

package main

import "fmt"

type Test struct {
    name string
}

func (t *Test) Close() {
    fmt.Println(t.name, " closed")
}
func main() {
    ts := []Test{{"a"}, {"b"}, {"c"}}
    for _, t := range ts {
        defer t.Close()
    }
}

输出结果:

c  closed
c  closed
c  closed

解决办法

1 多写一层调用

package main

import "fmt"

type Test struct {
    name string
}

func (t *Test) Close() {
    fmt.Println(t.name, " closed")
}
func Close(t Test) {
    t.Close()
}
func main() {
    ts := []Test{{"a"}, {"b"}, {"c"}}
    for _, t := range ts {
        defer Close(t)
    }
}

输出结果:

 c  closed
 b  closed
 a  closed

2 写传入参数的闭包

package main

import "fmt"

type Test struct {
    name string
}


func main() {
    ts := []Test{{"a"}, {"b"}, {"c"}}
    for _, t := range ts {
        defer func(t Test){
        fmt.Println(t.name, " closed")}(t)
    }
}

3 重新声明

package main

import "fmt"

type Test struct {
    name string
}

func (t *Test) Close() {
    fmt.Println(t.name, " closed")
}
func main() {
    ts := []Test{{"a"}, {"b"}, {"c"}}
    for _, t := range ts {
        t := t
        defer t.Close()
    }
}

channel中的例子

package main

import (
	"fmt"
	"time"
)

func main() {
	info := make(chan string) 
	go send(info)

	for w := range info {
		go func() {
			time.Sleep(600 * time.Millisecond)
			fmt.Println(w)
		}()
	}

	time.Sleep(1000 * time.Millisecond)
}

func send(info chan string) {
	word := [...]string{"A", "B", "C", "D", "E", "F"}
	for _, s := range word {
		info <- s 
	}
	close(info) 
}

输出结果:

F
F
F
F
F
F

同样解决方法

1 写传入参数的闭包

package main

import (
	"fmt"
	"time"
)

func main() {
	info := make(chan string)
	go send(info)

	for w := range info {
		go func(w string) {
			time.Sleep(600 * time.Millisecond)
			fmt.Println(w)
		}(w) // 作为实参传入
	}

	time.Sleep(1000 * time.Millisecond)
}


func send(info chan string) {
	word := [...]string{"A", "B", "C", "D", "E", "F"}
	for _, s := range word {
		info <- s 
	}
	close(info)
}

输出结果:

E
B
A
C
F
D

2 重新声明

package main

import (
	"fmt"
	"time"
)

func main() {
	info := make(chan string) 
	go send(info)

	for w := range info {
		w := w 
		go func() {
			time.Sleep(600 * time.Millisecond)
			fmt.Println(w)
		}()
	}

	time.Sleep(1000 * time.Millisecond)
}


func send(info chan string) {
	word := [...]string{"A", "B", "C", "D", "E", "F"}
	for _, s := range word {
		info <- s 
	}
	close(info) 
}

在defer函数定义时,对外部变量的引用是有两种方式的,分别是作为函数参数和作为闭包引用。

作为函数参数,则在defer定义时就把值传递给defer,并被cache起来;
作为闭包引用的话,则会在defer函数真正调用时根据整个上下文确定当前的值。
defer后面的语句在执行的时候,函数调用的参数会被保存起来,也就是复制了一份。真正执行的时候,实际上用到的是这个复制的变量,因此如果此变量是一个“值”,那么就和定义的时候是一致的。如果此变量是一个“引用”,那么就可能和定义的时候不一致。

defre写闭包需要传入参数

 类似资料:

相关阅读

相关文章

相关问答