A Tour of Goの練習問題を解説するシリーズ(4/11) – Exercise: Fibonacci closure

みなさん、こんにちは。人類をGopherにしたいと考えているまるりんです。

A Tour of Goはプログラミング言語Goの入門サイトです。 このシリーズではA Tour of Goの練習問題を解説します。

今回は以下の問題を扱います。

問題
Exercise: Fibonacci closure
解答
https://go.dev/play/p/UK_MC_Ik632


この問題には初学者が理解しづらいと思われる2つの概念が含まれています。

  • フィボナッチ数列
  • クロージャ

フィボナッチ数列は以下のような数列です。

0, 1, 1, 2, 3, 5, 8, 13, 21, ...

数列の中にある2という値はどのように決定されるのでしょうか。2は、2の直前にある1とさらにその直前にある1との和です。 8であれば直前の5とさらに直前の3との和で求められます。つまり第n項はn-1項とn-2項を足すことにより求められます。

次にクロージャです。クロージャは説明するのが難しい概念です。要はオブジェクト指向におけるインスタンスだと理解しましょう。 前ページにある、pos, neg := adder(), adder()pos, neg := new adder(), new adder()ととらえるとpos()、neg()用の変数sumが使えて関数を抜けてもsumが値を保持している、ということが直感的に理解できると思います。 概念理解のためにサンプルコードを作ってみました。

ソース
https://go.dev/play/p/mZ76AQvXGng

実行結果

10
20
10
20
12
24

問題を解くための前提条件を理解しました。 クロージャはローカル変数の値を保持できるので、何らかの値を記憶させておきたいところです。 変数の初期値をn項とn+1項にし、クロージャの戻り値をn項とします。初回呼び出し時のnは1で初項は0です。 戻り値が確定した後で、n項の値をn+1項にし、n+1項の値をn+2項(n項+n+1項)にします。つまり隣り合う2つの変数が見ている数列の各値を1つずつ右側にずらした形になります。 この関数をn回呼べばn項の値を返します。素朴な実装をしたところ以下のようになりました。

ソース
https://go.dev/play/p/UK_MC_Ik632

実行結果

0
1
1
2
3
5
8
13
21
34

ネットの解答では初期値を逆にして一時変数を使わないやり方が載っていましたが、この解答の方が論理とコードが対応づいていて分かりやすくて良いと思います。