GO匿名関数とクローズド
匿名関数:名前の通り名前のない関数です。java、js、phpなど多くの言語があります。その中でjsが一番好きです。匿名関数の最大の用途は、データ汚染を避けるためにブロックレベルのスコープをシミュレートすることである。
今日は主にGolang言語の匿名関数とクローズドについて話します。
匿名関数
例:
1、
パッケージを閉じます。つまり関数のネストです。内部の関数は外層関数のすべての変数を使ってもいいです。外層関数はすでに実行済みです。
例:
1、
3、
4、上記のバグを避けるには、以下の方法で上記の例と比較するように注意してください。
5、
6、再帰関数
もう一つの場合は、全部を使って閉じなければならないということです。つまり、再帰関数です。
この数列は第3項から始まります。各項目は前の2項の合計に等しいです。
匿名関数とクローズドは同じです。匿名関数はクローズドです。匿名関数はプログラミングに柔軟性を与え、バグも発生しやすく、関数のパラメータや受け入れ可能なパラメータに注意する必要があります。
linksディレクトリ
今日は主にGolang言語の匿名関数とクローズドについて話します。
匿名関数
例:
1、
package main
import (
"fmt"
)
func main() {
f:=func(){
fmt.Println("hello world")
}
f()//hello world
fmt.Printf("%T
", f) // func()
}
2、パラメータ付きpackage main
import (
"fmt"
)
func main() {
f:=func(args string){
fmt.Println(args)
}
f("hello world")//hello world
//
(func(args string){
fmt.Println(args)
})("hello world")//hello world
//
func(args string) {
fmt.Println(args)
}("hello world") //hello world
}
3、戻り値付きpackage main
import "fmt"
func main() {
f:=func()string{
return "hello world"
}
a:=f()
fmt.Println(a)//hello world
}
4、複数の匿名関数package main
import "fmt"
func main() {
f1,f2:=F(1,2)
fmt.Println(f1(4))//6
fmt.Println(f2())//6
}
func F(x, y int)(func(int)int,func()int) {
f1 := func(z int) int {
return (x + y) * z / 2
}
f2 := func() int {
return 2 * (x + y)
}
return f1,f2
}
クローズド(closure)パッケージを閉じます。つまり関数のネストです。内部の関数は外層関数のすべての変数を使ってもいいです。外層関数はすでに実行済みです。
例:
1、
package main
import "fmt"
func main() {
a := Fun()
b:=a("hello ")
c:=a("hello ")
fmt.Println(b)//hello world
fmt.Println(c)//worldhello hello
}
func Fun() func(string) string {
a := "world"
return func(args string) string {
a += args
return a
}
}
2、package main
import "fmt"
func main() {
a := Fun()
d := Fun()
b:=a("hello ")
c:=a("hello ")
e:=d("hello ")
f:=d("hello ")
fmt.Println(b)//hello world
fmt.Println(c)//worldhello hello
fmt.Println(e)//hello world
fmt.Println(f)//worldhello hello
}
func Fun() func(string) string {
a := "world"
return func(args string) string {
a += args
return a
}
}
注意F()を2回呼び出すと、同じa変数ではないように維持されます。3、
package main
import "fmt"
func main() {
a := F()
a[0]()//0xc00004c080 3
a[1]()//0xc00004c080 3
a[2]()//0xc00004c080 3
}
func F() []func() {
b := make([]func(), 3, 3)
for i := 0; i < 3; i++ {
b[i] = func() {
fmt.Println(&i,i)
}
}
return b
}
クローズドは、参照によって外部関数の変数を使用します。例では一度の関数Fのみが呼び出され、一つのクローズドパケットを構成し、iは外部関数Bで定義されるので、この変数iはクローズドで維持され、a[0]、a[1]、a[2]のiはすべてクローズド中iの参照である。したがって、iの値はすでに3になっていますので、a[0]()を呼び出した場合の出力は0ではなく3です。4、上記のバグを避けるには、以下の方法で上記の例と比較するように注意してください。
package main
import "fmt"
func main() {
a := F()
a[0]() //0xc00000a0a8 0
a[1]() //0xc00000a0c0 1
a[2]() //0xc00000a0c8 2
}
func F() []func() {
b := make([]func(), 3, 3)
for i := 0; i < 3; i++ {
b[i] = (func(j int) func() {
return func() {
fmt.Println(&j, j)
}
})(i)
}
return b
}
package main
import "fmt"
func main() {
a := F()
a[0]() //0xc00004c080 0
a[1]() //0xc00004c088 1
a[2]() //0xc00004c090 2
}
func F() []func() {
b := make([]func(), 3, 3)
for i := 0; i < 3; i++ {
j := i
b[i] = func() {
fmt.Println(&j, j)
}
}
return b
}
各動作は、匿名関数を配列に入れるだけで実行されず、参照変数はi
であり、i
の変更に伴い、匿名関数のi
も変化しているので、これらの関数を実行すると、環境変数i
の最後の値が読み取られる。解決策は、複製変数i
のたびに、次いで匿名関数に送られて、クローズドされた環境変数が異なるようにすることである。5、
package main
import "fmt"
func main() {
fmt.Println(F())//2
}
func F() (r int) {
defer func() {
r++
}()
return 1
}
出力結果は2です。つまり、r=1を先に実行して、r++を実行します。6、再帰関数
もう一つの場合は、全部を使って閉じなければならないということです。つまり、再帰関数です。
package main
import "fmt"
func F(i int) int {
if i <= 1 {
return 1
}
return i * F(i-1)
}
func main() {
var i int = 3
fmt.Println(i, F(i))// 3 6
}
7、フィボナッチ数列(フィボナッチ)この数列は第3項から始まります。各項目は前の2項の合計に等しいです。
package main
import "fmt"
func fibonaci(i int) int {
if i == 0 {
return 0
}
if i == 1 {
return 1
}
return fibonaci(i-1) + fibonaci(i-2)
}
func main() {
var i int
for i = 0; i < 10; i++ {
fmt.Printf("%d
", fibonaci(i))
}
}
リボン:匿名関数とクローズドは同じです。匿名関数はクローズドです。匿名関数はプログラミングに柔軟性を与え、バグも発生しやすく、関数のパラメータや受け入れ可能なパラメータに注意する必要があります。
links