关于Golang中的lambda函数/闭包,我有一些困惑。

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

some confusions about lambda function/closure in Golang

问题

package main
import (
    "fmt"
)
func main(){
    f,val,val1:=fibonacci()
    fmt.Println(val,val1)
    for i:=0;i<=10;i++ {
        fmt.Println(f(i),val,val1)
    }
    _,val,val1=fibonacci()
    fmt.Println(val,val1)
}
func fibonacci()(func(n int)int,int,int){
    var val int
    var val1 int
    f:=func(n int)int{
        if n==0||n==1{
            val,val1=1,1
        }else{
            val,val1=val+val1,val
        }
        return val
    }
    fmt.Println("fibonacci val =",val,"val1 =",val1)
    return f,val,val1
}

这是我解决斐波那契数列问题的代码,没有使用递归,而是使用了 lambda 函数/闭包。Go 文档中说闭包会捕获一些外部状态。我的理解是闭包会保留函数声明时的状态的副本。这些状态只是副本,无论我对它们做什么修改,都不会影响原始状态,是这样吗?

英文:
package main
import (
    &quot;fmt&quot;
)
func main(){
    f,val,val1:=fibonacci()
    fmt.Println(val,val1)
    for i:=0;i&lt;=10;i++ {
        fmt.Println(f(i),val,val1)
    }
    _,val,val1=fibonacci()
    fmt.Println(val,val1)
}
func fibonacci()(func(n int)int,int,int){
    var val int
    var val1 int
    f:=func(n int)int{
        if n==0||n==1{
            val,val1=1,1
        }else{
            val,val1=val+val1,val
        }
        return val
    }
    fmt.Println(&quot;fibonacci val =&quot;,val,&quot;val1 =&quot;,val1)
    return f,val,val1
}

> Here is my code on sloving fibonacci without using recursion when I
> read about lambda function/closure. And the Go Documentary says a
> closure will capture some external state. My understanding is the
> closure will keep a copy of state of the function which it is
> declared. These states are just copies whatever I do on them won't
> modify the original, is that so?

答案1

得分: 0

根据你提供的代码,我给你翻译如下:

从你的测试代码中https://play.golang.org/p/pajT2bAIe2

你的 fibonacci 函数在以增量方式调用时可以计算出序列中的第 n 个数字但是你从对 `fibonacci` 的初始调用中返回的值不是指向那些整数值的指针或引用),它们只是那些整数在那个时间点的值可以将它们视为从函数中复制出来的值尝试改用整数指针像这样https://play.golang.org/p/-vLja7Fpsq

    package main
    
    import (
    	"fmt"
    )
    
    func main() {
    	f, val, val1 := fibonacci()
    	fmt.Println(val, val1)
    	for i := 0; i <= 10; i++ {
    		fmt.Println(f(i), *val, *val1) // 解引用指针以获取当前时间的值
    	}
    	_, val, val1 = fibonacci()
    	fmt.Println(*val, *val1)
    }
    
    func fibonacci() (func(n int) int, *int, *int) {
    	var val int
    	var val1 int
    	f := func(n int) int {
    		if n == 0 || n == 1 {
    			val, val1 = 1, 1
    		} else {
    			val, val1 = val+val1, val
    		}
    		return val
    	}
    	fmt.Println("fibonacci val =", val, "val1 =", val1)
    	return f, &val, &val1 // 返回闭包值的指针,而不仅仅是值本身
    }

希望对你有帮助!如果有任何问题,请随时提问。

英文:

from your test code here: https://play.golang.org/p/pajT2bAIe2

your fibonacci function is working out the nth numbers in the sequence provided it's called in an incremental fashion as you are doing. but the values you return from the initial call to fibonacci are not pointers (or references) to those integer values they are just the values of those integers at that time, think of them as being copied out of the function, try using integer pointers instead like this: https://play.golang.org/p/-vLja7Fpsq

package main

import (
	&quot;fmt&quot;
)

func main() {
	f, val, val1 := fibonacci()
	fmt.Println(val, val1)
	for i := 0; i &lt;= 10; i++ {
		fmt.Println(f(i), *val, *val1) //dereference the pointer to get its value at the current time
	}
	_, val, val1 = fibonacci()
	fmt.Println(*val, *val1)
}
func fibonacci() (func(n int) int, *int, *int) {
	var val int
	var val1 int
	f := func(n int) int {
		if n == 0 || n == 1 {
			val, val1 = 1, 1
		} else {
			val, val1 = val+val1, val
		}
		return val
	}
	fmt.Println(&quot;fibonacci val =&quot;, val, &quot;val1 =&quot;, val1)
	return f, &amp;val, &amp;val1 // return pointers to the closured values instead of just the values
}

答案2

得分: 0

虽然你已经接受了上面的答案,但我给出另一个解释。你之所以收到循环操作的最后一个值,是因为Go语言的词法作用域。for循环引入了一个新的词法块,在该块中,该值通过其内存地址引用,而不是通过其值引用。为了获取该值,你需要进行解引用。

每次循环迭代时,处理的值都指向同一个内存地址。由此循环创建的所有函数值都会“捕获”并共享相同的变量 - 可寻址的存储位置,而不是该特定时刻的值。因此,当最后一次迭代完成时,变量保存的是最后一步的值。

对于这种类型的操作,更好的方法是使用goroutine,因为在这些情况下,你不是通过共享相同的内存地址进行通信,而是通过通信来共享内存。

以下是使用goroutine的更优雅的解决方案:

package main

import (
	"fmt"
)

func fibonacci(ch chan interface{}, quit chan struct{}) {
	x, y := 1, 1
	for {
		select {
		case ch <- x:
			x, y = y, x+y
			fmt.Println(x, y)
		case <-quit:
			fmt.Println("Quiting...")
			return
		}
	}
}

func main() {
	ch := make(chan interface{})
	quit := make(chan struct{})

	go func() {
		for i := 0; i < 10; i++ {
			<-ch
		}
		quit <- struct{}{}
	}()

	fibonacci(ch, quit)
}

你可以在这里查看运行示例:https://play.golang.org/p/oPQgXWyV9u

英文:

Although you have accepted the above answer i'm giving another explanation. The reason why you receive the last value of the loop operation has to do with the Go's lexical scoping. The for loop introduces a new lexical block in which the value is referenced by it's memory address, so by pointer and not by it's value. In order to get the value, you have to de-reference.

Each time the for loop makes an iteration the value processed is pointing to the same memory address. All the function values created by this loop "capture" and share the same variable - and addressable storage location, not it's value at that particular moment. Thus when the last iteration is finished, the variable holds the value from the final step.

A much better approach for these kind of operations would be to use goroutines, because in these cases you are not communicating through sharing the same memory address, but you are sharing the memory through communication.

Here is a more elegant solution using goroutine:

package main

import (
	&quot;fmt&quot;
)

func fibonacci(ch chan interface{}, quit chan struct{}) {
	x, y := 1, 1
	for {
		select {
		case ch &lt;- x:
			x, y = y, x+y
			fmt.Println(x , y)
		case &lt;-quit:
			fmt.Println(&quot;Quiting...&quot;)
			return
		}
	}
}

func main() {
	ch := make(chan interface{})
	quit := make(chan struct{})

	go func() {
		for i := 0; i &lt; 10; i++ {
			&lt;-ch
		}
		quit &lt;- struct{}{}
	}()

	fibonacci(ch, quit)
}

https://play.golang.org/p/oPQgXWyV9u

huangapple
  • 本文由 发表于 2016年12月6日 16:18:57
  • 转载请务必保留本文链接:https://go.coder-hub.com/40990735.html
匿名

发表评论

匿名网友

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

确定