閉鎖が主流のプログラミング言語で一般的な技術、そして多くの場合、関数型プログラミングの強力な組み合わせ、本論文では導入することであるGo
クロージャとは何かの言語どのようにクロージャを理解するためにします。
以下のための読者ならばGo
、言語の閉鎖が特に明確ではないが、あなたができる前の記事を参照して 、外出先の研究では、それだけで何ができるクロージャの明確な例が必要であることを指摘します。
それともあなたがすることができます直接無視するあなたがだろうから、先行詞要約を思い出し、今、あなたは準備ができています?Go
!
フィボナッチ列は、クロージャを見ます
かどうかGo
の閉鎖を説明するために、公式サイトや他のオンラインチュートリアル、常に見ることができフィボナッチ列の数字を、例を示し古典を!
数フィボナッチ(
Fibonacci sequence
としても知られている)、黄金列。ための数学レオナルドフィボナッチ(Leonardoda Fibonacci
へ)ウサギ飼育例としての導入、それはまた、を参照し、「ウサギの列」として知られています列数:1、1、2、3、5、8、13、21、34、……
数学、フィボナッチ数が記載されている以下では、再帰的な方法で定義されています:F(1)=1,F(2)=1, F(n)=F(n-1)+F(n-2)(n>=3,n∈N*)
現代物理学、準結晶構造、化学の分野では、シーケンスは、このための直接的なアプリケーションを持っている、アメリカの数学のフィボナッチ1963年以来、名前に「フィボナッチ季刊」数学と雑誌の発行、この分野の研究に専念しています。
よる百度百科事典については、我々は知っているフィボナッチ列が形状に形成されている1 1 2 3 5 8 13 21 34 55
から、列の増加第三の開始、現在の項目は、最初の2つの合計です。
二つの変数の定義は、計算を容易にするために、a,b
最初の二つを示し、初期値に設定されている0,1
例:
// 0 1 1 2 3 5 8 13 21 34 55
// a b
// a b
a, b := 0, 1
運動の次のラウンドを初期化した後、a, b = b, a+b
結果があるa , b = 1 , 1
だけで表現するために、フィボナッチ列を開始します。
「スノードリームイン技術は、」想像した場合
a,b
、変数の初期値は1,1
、ロジックを変更せずに、最後の列によって生成されたその行為のフィボナッチ数は何ですか?
func fibonacciByNormal() {
a, b := 0, 1
a, b = b, a+b
fmt.Print(a, " ")
fmt.Println()
}
しかし、上記の例では、のみ生成することができフィボナッチ数を、我々が必要な場合は、最初の数で最初の10列をどのように、?
func fibonacciByNormal() {
a, b := 0, 1
for i := 0; i < 10; i++ {
a, b = b, a+b
fmt.Print(a, " ")
}
fmt.Println()
}
指定されたサイクル数、次いでわずかに上記特異列コードを変更、今生成することができる10個の列が。
// 1 1 2 3 5 8 13 21 34 55
func TestFibonacciByNormal(t *testing.T) {
fibonacciByNormal()
}
このアプローチは、私が達成することができますいくつかの小さなプログラミング経験の開発者があると信じて、我々は解決策が採用されているフロントホックのコンセプトに接触しているが、閉鎖は、別のアイデアを提供してきました!
// 1 1 2 3 5 8 13 21 34 55
func fibonacci() func() int {
a, b := 0, 1
return func() int {
a, b = b, a+b
return a
}
}
通常の関数またはフィボナッチ列ロジック生成機能を実現する機能クロージャが同じであるかどうか、だけ、内部関数を返す異なるクロージャを実現するためにユーザがコールを継続残すされ、通常の機能を直接生成フィボナッチ番号の。
// 1 1 2 3 5 8 13 21 34 55
func TestFibonacci(t *testing.T) {
f := fibonacci()
for i := 0; i < 10; i++ {
fmt.Print(f(), " ")
}
fmt.Println()
}
別の関数内にネストされ、この内部関数および関数リファレンス「閉鎖」と呼ばれるような実装外部変数、のために!
「スノードリームインテクノロジー」:クロージャがある機能+リファレンス環境の両方が不可欠である、有機全組成、を参照してください研究を行ってそれだけで何ができるクロージャの明確な例が必要であることを指摘。
独自の独立した動作環境
「スノードリームイン技術は、」:オペレーティング環境に付属している映画出演など閉鎖の自身のバックグラウンドミュージック音楽が聞こえた、のように、チョウの、毛Gedengフィールド、閉鎖が発生し、環境が来ます!
閉鎖自身別個のオペレーティング環境は、各実行クロージャは、オブジェクト指向のように、環境から独立しているクラスおよびオブジェクトタイプのクロージャとして関係のインスタンスを、閉鎖参照オブジェクトがインスタンスです。
func autoIncrease() func() int {
i := 0
return func() int {
i = i + 1
return i
}
}
上述の例示的な閉鎖が増加計算達成される、すべての基準autoIncrease
閉鎖環境機能は、直接ユニットテストケースに、得ることがお互いに独立しています。
func TestAutoIncrease(t *testing.T) {
a := autoIncrease()
// 1 2 3
t.Log(a(), a(), a())
b := autoIncrease()
// 1 2 3
t.Log(b(), b(), b())
}
関数参照a
とb
環境が独立している、別の同一カウンタの同等は再びカウントを開始し、元のカウンタの業績に影響を与えることはありません。
「スノードリームインテクノロジー」:閉鎖はただではない機能を、より重要である環境。それが閉鎖機能参照されるたびに、ビューの業績ポイントから動作環境再初期化し、このメカニズムのは、オブジェクト指向と非常によく似ているクラスとインスタンスオブジェクトの関係!
不死は、祝福や呪いであります
システム稼働の関数の最後は、彼の短いと輝かしい人生を終了、破棄された後、限られた寿命を定義した内部変数の正常な機能。
しかし、参照クロージャ変数は、同じではありません限りであったようで、使用状態、その変数は、「だろう永遠に生きる」と機能で生まれ、一般の変数が同じ短い寿命を持っていることはありません。
- 古い馬、高い志
func fightWithHorse() func() int {
horseShowTime := 0
return func() int {
horseShowTime++
fmt.Printf("(%d)祖国需要我,我就提枪上马立即战斗!\n",horseShowTime)
return horseShowTime
}
}
func TestFightWithHorse(t *testing.T) {
f := fightWithHorse()
// 1 2 3
t.Log(f(), f(), f())
}
「スノードリームインテクノロジー」:ユーザーは、関数クロージャを使用している場合は、内部参照が破壊されることはありません自由変数の閉鎖は、されているアクティブな状態が得られるように、永遠の命の超大国を!
- 不幸はVでふにふに西災害によって依拠しました
すべて良い基盤は、ということに不滅参照変数アンデッドの閉鎖は、あなたが変数理解していない場合は、不死の誤っ閉鎖機能書き込むときに陥るかもしれプロパティスコープトラップを、気をつけてください!
例えば、変数バインディングループ閉鎖スコープトラップを説明するための例下:
func countByClosureButWrong() []func() int {
var arr []func() int
for i := 1; i <= 3; i++ {
arr = append(arr, func() int {
return i
})
}
return arr
}
countByClosureButWrong
自由変数クロージャ関数参照するだけでなくarr
、配列だけでなく、ループ変数をi
、全体的な論理機能は次のとおりです。機能、機能の閉鎖内部配列を維持する主な機能を保存するためには、ループ変数を返します。
func TestCountByClosure(t *testing.T) {
// 4 4 4
for _, c := range countByClosureButWrong() {
t.Log(c())
}
}
我々は実行すると、countByClosureButWrong
クロージャを返す関数の配列を取得する機能をarr
、そしてrange
、配列のキーワードをトラバース機能の用語が横断され得ますc
。
我々は実行するとc()
、所望の出力1,2,3
ループ変数の値が、実際の結果があります4,4,4
。
その理由はまだ不滅変数の特性である:ループトラバースするときバインディング変数値確かに1,2,3
、しかし、ループ変数をi
ではなく、通常の関数のように死ぬとしてではなく、永遠にされているので、変数の参照は変更さ!
ループ変数の値は、正確に不死元のループの終了条件であるi=4
アレイのうち同一の機能参照変数であるにかかわらず、限り、操作機能クロージャi
ので、すべてです、4,4,4
。
それは変数参照の問題であるので、それのような何の変数の参照、それは非常に簡単です解決しません!
最も簡単な方法は、短い使用することです一時変数は、 n
一時的に横断されている値を格納し、クロージャ内の変数の参照は、もはやありませんi
が、一時的な変数n
。
func countByClosureButWrong() []func() int {
var arr []func() int
for i := 1; i <= 3; i++ {
n := i
fmt.Printf("for i=%d n=%d \n", i,n)
arr = append(arr, func() int {
fmt.Printf("append i=%d n=%d\n", i, n)
return n
})
}
return arr
}
上記の溶液をするだけだったループ変数の一時的な変数バインディングの値を採用し、むしろ元不死変数の参照よりも、しかし、このような行為は、エレガントではないですが、また、アップグレードバージョンを簡素化するために続けています。
それが使用されるので、変数代入プラクティス、およびないで渡されたパラメータ転送の値が非常に似ている?その後、我々は、転送値によって閉鎖関数に渡された変数の値を再コピーすることができます。
func countByClosureWithOk() []func() int {
var arr []func() int
for i := 1; i <= 3; i++ {
fmt.Printf("for i=%d \n", i)
func(n int) {
arr = append(arr, func() int {
fmt.Printf("append n=%d \n", n)
return n
})
}(i)
}
return arr
}
「スノードリームインテクノロジー」:引数を渡す方法による自己実行匿名関数
i
、内部関数は、変数を使用n
、外部ループ変数を結合し、よりエレガントに見える、グリッドを余儀なくされています!
値変換によって渡された匿名関数を使用すると、我々は再び変換結果をテストするためのテストケースを実行します。
func TestCountByClosureWithOk(t *testing.T) {
// 1 2 3
for _, c := range countByClosureWithOk() {
t.Log(c())
}
}
最後に正しくループ変数を結合問題を解決し、そして実際の結果は、あなたが予想される次の時間が表示され、必ずしもではないbug
クロージャのいかなる適切な使用がない、深くない理解することが可能!
長所と短所について話して突入
- アナログクラスとオブジェクトの関係は、また、実現することができるパッケージをいくつかと、オブジェクト指向の機能
「スノードリームインテクノロジー」:各コール閉鎖機能環境は、互いに独立しており、オブジェクト指向のクラスとインスタンス化されたオブジェクト間の関係に似た特徴。
- キャッシュの乱用を避けるために複雑なロジック、メモリ常駐、グローバル変数メンテナンスコストを招待し。
「スノードリームインテクノロジー」:不滅の機能は閉鎖永久的なメモリ参照変数は、いくつかの複雑なロジックコードをキャッシュするために使用することができ作るには、元のグローバル変数の誤用を避けるために非常に適しています。
- 閉鎖高コストの実装だけでなく、増加の理解の難しさを。
「スノードリームインテクノロジー」:通常の関数はクロージャ関数に困難をある程度達成するためだけではなく、理解することは容易ではない、数回以上が必要ですが、テストの閉鎖の特性を理解していないだけ。
- 虐待が簡単にあまりにも多くのメモリを取る、それが引き起こす可能性がメモリリークを。
「スノードリームインテクノロジー」:クロージャの過度の使用は、参照変数を作成するためにバインドされている循環参照またはタイムリーではないガベージコレクションがメモリリークを引き起こす可能性がある場合には、永久的なメモリを持っています。
簡単な要約閉鎖知識
クロージャは一般的な技術であり、Go
言語サポートの閉鎖、主でGo
ネストされた無名関数内部のサポート機能が、Go
通常の関数のネストをサポートしていません。
シンプルで理解し、そして閉鎖は全体的な機能と一緒にした有機環境であり、動作環境の独立した参照変数と不死はクロージャの二つの重要な機能です。
、オブジェクト、等アナログオブジェクト指向機能を実装するかどうかをキャッシュまたはパッケージングアプリケーションは、両方の特性アプリケーションです。
最後に、私たちはそれが通る思い出してみましょうフィボナッチ列旅の閉鎖を終了するには!
func fibonacci() func() int {
a, b := 0, 1
return func() int {
a, b = b, a+b
return a
}
}
この記事では、サンプルコードに関する:https://github.com/snowdreams1006/learn-go/blob/master/functional/closure/closure_test.go
参考資料と参考資料
- コンセプトの閉鎖、フォームおよびアプリケーション
- Jarttoブログ:リフレクションズ閉鎖
- 閉鎖についての話:ブログを削除
-
この記事はあなたを助ける場合は、手のタッチをタップしてください推奨されるメッセージを残すと、必要に応じて、個人的な数字の国民意識してくださいそれ以外にも私を修正し、「スノードリームイン技術。」