List of Init - text.Baldanders.info
tag:text.Baldanders.info,2017-10-24:/tags
2017-10-24T14:43:01+09:00
帰ってきた「しっぽのさきっちょ」
https://text.baldanders.info/images/avatar.jpg
https://text.baldanders.info/images/avatar.jpg
Go 言語における Singleton Pattern
tag:text.Baldanders.info,2017-10-24:/golang/singleton-pattern/
2017-10-24T05:43:01+00:00
2021-11-28T02:58:44+00:00
はっきり言って「Singleton なめんな!」ですよ。
Spiegel
https://baldanders.info/profile/
<p>今回は小ネタでお送りします。</p>
<p>いや,ネットでね,<a href="https://golang.org/" title="The Go Programming Language">Go 言語</a>での Singleton 実装をこんな感じに書く人をやたら見かけるのだが</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-go" data-lang="go"><span class="line"><span class="cl"><span class="c1">//Hello class
</span></span></span><span class="line"><span class="cl"><span class="c1"></span><span class="kd">type</span> <span class="nx">Hello</span> <span class="kd">struct</span><span class="p">{}</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="kd">var</span> <span class="nx">instance</span> <span class="o">*</span><span class="nx">Hello</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="c1">//GetInstance returns singleton instance
</span></span></span><span class="line"><span class="cl"><span class="c1"></span><span class="kd">func</span> <span class="nf">GetInstance</span><span class="p">()</span> <span class="o">*</span><span class="nx">Hello</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl"> <span class="k">if</span> <span class="nx">instance</span> <span class="o">==</span> <span class="kc">nil</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl"> <span class="nx">instance</span> <span class="p">=</span> <span class="o">&</span><span class="nx">Hello</span><span class="p">{}</span>
</span></span><span class="line"><span class="cl"> <span class="p">}</span>
</span></span><span class="line"><span class="cl"> <span class="k">return</span> <span class="nx">instance</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span></code></pre></div><p>はっきり言って <strong>Singleton なめんな!</strong> ですよ。</p>
<p>そうそう。
プログラマで Singleton Pattern を知らない人はいないと思うけど,一応解説しておくと, Singleton Pattern というのは,あるクラスに対してプログラム全体でインスタンスがひとつだけ生成されるよう制限するプログラミング・パターンである。
たとえば,単一セッションでシリアルに通信を行う entity class なんかはインスタンスがぼこぼこできて各々勝手に処理をされると困るわけで<sup id="fnref:1"><a href="#fn:1" class="footnote-ref" role="doc-noteref">1</a></sup>, singleton インスタンスの内部で同期をとっていく必要があるわけ。</p>
<p>という説明からも分かると思うけど「<strong>スレッドセーフでない singleton 実装に存在意義はない</strong>」のである。
ちなみに結城浩さんの<a href="https://www.amazon.co.jp/exec/obidos/ASIN/B00I8AT1BS/baldandersinf-22/" title="増補改訂版 Java言語で学ぶデザインパターン入門 マルチスレッド編 | 結城 浩 | コンピュータ・IT | Kindleストア | Amazon">デザパタ本</a>にあるサンプルコードも以下のようになっている(こっちは Java での記述だけど<sup id="fnref:2"><a href="#fn:2" class="footnote-ref" role="doc-noteref">2</a></sup>)。</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-java" data-lang="java"><span class="line"><span class="cl"><span class="kn">import</span><span class="w"> </span><span class="nn">java.util.Date</span><span class="p">;</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="kd">public</span><span class="w"> </span><span class="kd">class</span> <span class="nc">MySystem</span><span class="w"> </span><span class="p">{</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="kd">private</span><span class="w"> </span><span class="kd">static</span><span class="w"> </span><span class="n">MySystem</span><span class="w"> </span><span class="n">instance</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="kc">null</span><span class="p">;</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="kd">private</span><span class="w"> </span><span class="n">Date</span><span class="w"> </span><span class="n">date</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="k">new</span><span class="w"> </span><span class="n">Date</span><span class="p">();</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="kd">private</span><span class="w"> </span><span class="nf">MySystem</span><span class="p">()</span><span class="w"> </span><span class="p">{</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="p">}</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="kd">public</span><span class="w"> </span><span class="n">Date</span><span class="w"> </span><span class="nf">getDate</span><span class="p">()</span><span class="w"> </span><span class="p">{</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="k">return</span><span class="w"> </span><span class="n">date</span><span class="p">;</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="p">}</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="kd">public</span><span class="w"> </span><span class="kd">static</span><span class="w"> </span><span class="kd">synchronized</span><span class="w"> </span><span class="n">MySystem</span><span class="w"> </span><span class="nf">getInstance</span><span class="p">()</span><span class="w"> </span><span class="p">{</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="k">if</span><span class="w"> </span><span class="p">(</span><span class="n">instance</span><span class="w"> </span><span class="o">==</span><span class="w"> </span><span class="kc">null</span><span class="p">)</span><span class="w"> </span><span class="p">{</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="n">instance</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="k">new</span><span class="w"> </span><span class="n">MySystem</span><span class="p">();</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="p">}</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="k">return</span><span class="w"> </span><span class="n">instance</span><span class="p">;</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="p">}</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="p">}</span><span class="w">
</span></span></span></code></pre></div><p><code>static</code> で <code>synchronized</code> なのがポイントね。
つまり,実際にインスタンスを生成する処理では何らかの手段でスレッドセーフであることが保証されてないといけない<sup id="fnref:3"><a href="#fn:3" class="footnote-ref" role="doc-noteref">3</a></sup>。
最初の <a href="https://golang.org/" title="The Go Programming Language">Go 言語</a>のパターンが何故ダメなのかは実際に動くコードを書いてみれば分かる。</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-go" data-lang="go"><span class="line"><span class="cl"><span class="kn">package</span> <span class="nx">main</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="kn">import</span> <span class="p">(</span>
</span></span><span class="line"><span class="cl"> <span class="s">"fmt"</span>
</span></span><span class="line"><span class="cl"> <span class="s">"time"</span>
</span></span><span class="line"><span class="cl"><span class="p">)</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="c1">//Hello class
</span></span></span><span class="line"><span class="cl"><span class="c1"></span><span class="kd">type</span> <span class="nx">Hello</span> <span class="kd">struct</span><span class="p">{}</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="kd">func</span> <span class="p">(</span><span class="nx">h</span> <span class="o">*</span><span class="nx">Hello</span><span class="p">)</span> <span class="nf">String</span><span class="p">()</span> <span class="kt">string</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl"> <span class="k">return</span> <span class="s">"Hello"</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="kd">var</span> <span class="nx">instance</span> <span class="o">*</span><span class="nx">Hello</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="c1">//GetInstance returns singleton instance
</span></span></span><span class="line"><span class="cl"><span class="c1"></span><span class="kd">func</span> <span class="nf">GetInstance</span><span class="p">()</span> <span class="o">*</span><span class="nx">Hello</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl"> <span class="k">if</span> <span class="nx">instance</span> <span class="o">==</span> <span class="kc">nil</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl"> <span class="nx">fmt</span><span class="p">.</span><span class="nf">Println</span><span class="p">(</span><span class="s">"new instance"</span><span class="p">)</span>
</span></span><span class="line"><span class="cl"> <span class="nx">time</span><span class="p">.</span><span class="nf">Sleep</span><span class="p">(</span><span class="mi">1</span> <span class="o">*</span> <span class="nx">time</span><span class="p">.</span><span class="nx">Second</span><span class="p">)</span> <span class="c1">//delay 1sec
</span></span></span><span class="line"><span class="cl"><span class="c1"></span> <span class="nx">instance</span> <span class="p">=</span> <span class="o">&</span><span class="nx">Hello</span><span class="p">{}</span>
</span></span><span class="line"><span class="cl"> <span class="p">}</span>
</span></span><span class="line"><span class="cl"> <span class="k">return</span> <span class="nx">instance</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="kd">func</span> <span class="nf">main</span><span class="p">()</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl"> <span class="nx">ch</span> <span class="o">:=</span> <span class="nb">make</span><span class="p">(</span><span class="kd">chan</span> <span class="kd">interface</span><span class="p">{})</span>
</span></span><span class="line"><span class="cl"> <span class="k">go</span> <span class="nf">run</span><span class="p">(</span><span class="nx">ch</span><span class="p">,</span> <span class="s">"Alice"</span><span class="p">)</span>
</span></span><span class="line"><span class="cl"> <span class="k">go</span> <span class="nf">run</span><span class="p">(</span><span class="nx">ch</span><span class="p">,</span> <span class="s">"Bob"</span><span class="p">)</span>
</span></span><span class="line"><span class="cl"> <span class="k">go</span> <span class="nf">run</span><span class="p">(</span><span class="nx">ch</span><span class="p">,</span> <span class="s">"Chris"</span><span class="p">)</span>
</span></span><span class="line"><span class="cl"> <span class="o"><-</span><span class="nx">ch</span>
</span></span><span class="line"><span class="cl"> <span class="o"><-</span><span class="nx">ch</span>
</span></span><span class="line"><span class="cl"> <span class="o"><-</span><span class="nx">ch</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="kd">func</span> <span class="nf">run</span><span class="p">(</span><span class="nx">ch</span> <span class="kd">chan</span><span class="o"><-</span> <span class="kd">interface</span><span class="p">{},</span> <span class="nx">person</span> <span class="kt">string</span><span class="p">)</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl"> <span class="nx">hello</span> <span class="o">:=</span> <span class="nf">GetInstance</span><span class="p">()</span>
</span></span><span class="line"><span class="cl"> <span class="nx">ch</span> <span class="o"><-</span> <span class="nx">hello</span> <span class="c1">//blocking
</span></span></span><span class="line"><span class="cl"><span class="c1"></span> <span class="nx">fmt</span><span class="p">.</span><span class="nf">Println</span><span class="p">(</span><span class="nx">hello</span><span class="p">,</span> <span class="nx">person</span><span class="p">)</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span></code></pre></div><p>簡単に説明すると,まず <code>GetInstance()</code> 関数内部で初期化処理時間を演出するために1秒間の delay を発生させている。
<code>run()</code> 関数内で <a href="http://golang.org/ref/spec#Channel_types" title="The Go Programming Language Specification - The Go Programming Language">channel</a> <code>ch</code> にインスタンスを食わせているのはブロッキングのため。
別に何を食わせてもいいのだが,手近に <code>GetInstance()</code> 関数で取得したインスタンスがあるので,それを食わせている。
<code>main()</code> 関数では <code>run()</code> 関数を <a href="http://golang.org/ref/spec#Go_statements" title="The Go Programming Language Specification - The Go Programming Language">goroutine</a> で3連続起動したあと, <code><-ch</code> でブロックを解除している。</p>
<p><a href="https://play.golang.org/p/cL-RMmS2ev">実行結果</a>は以下の通り。</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-text" data-lang="text"><span class="line"><span class="cl">new instance
</span></span><span class="line"><span class="cl">new instance
</span></span><span class="line"><span class="cl">new instance
</span></span><span class="line"><span class="cl">Hello Alice
</span></span><span class="line"><span class="cl">Hello Chris
</span></span><span class="line"><span class="cl">Hello Bob
</span></span></code></pre></div><p>並行処理下の3つの <code>run()</code> 関数に対してインスタンスが3つ生成されてしまっているのが分かると思う。</p>
<p>ではどう書けばいいのか。
一番簡単なのは <a href="https://go.dev/ref/spec#Variables" title="The Go Programming Language Specification - The Go Programming Language">var</a> 宣言時に初期化してしまうことである。</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-go" data-lang="go"><span class="line"><span class="cl"><span class="kd">var</span> <span class="nx">instance</span> <span class="p">=</span> <span class="o">&</span><span class="nx">Hello</span><span class="p">{}</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="c1">//GetInstance returns singleton instance
</span></span></span><span class="line"><span class="cl"><span class="c1"></span><span class="kd">func</span> <span class="nf">GetInstance</span><span class="p">()</span> <span class="o">*</span><span class="nx">Hello</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl"> <span class="k">return</span> <span class="nx">instance</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span></code></pre></div><p>次に簡単なのは <a href="https://golang.org/doc/effective_go.html#init" title="Effective Go - The Go Programming Language"><code>init()</code></a> 関数を使うことである。</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-go" data-lang="go"><span class="line"><span class="cl"><span class="kd">var</span> <span class="nx">instance</span> <span class="o">*</span><span class="nx">Hello</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="kd">func</span> <span class="nf">init</span><span class="p">()</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl"> <span class="c1">//create instance and initialize
</span></span></span><span class="line"><span class="cl"><span class="c1"></span> <span class="nx">instance</span> <span class="p">=</span> <span class="o">&</span><span class="nx">Hello</span><span class="p">{}</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span></code></pre></div><p><a href="https://golang.org/doc/effective_go.html#init" title="Effective Go - The Go Programming Language"><code>init()</code></a> 関数は少し特殊な関数で,<code>main()</code> 関数がキックされる前,パッケージ内の <a href="https://go.dev/ref/spec#Variables" title="The Go Programming Language Specification - The Go Programming Language">var</a> 宣言時の初期化の後に呼ばれる。
ひとつのパッケージ内またはひとつのファイル内にいくつも <a href="https://golang.org/doc/effective_go.html#init" title="Effective Go - The Go Programming Language"><code>init()</code></a> 関数を設置できるのが特徴なのだが,どういう順番に起動するかは言語仕様として明記されていないため<sup id="fnref:4"><a href="#fn:4" class="footnote-ref" role="doc-noteref">4</a></sup>,パッケージ内の複数の <a href="https://golang.org/doc/effective_go.html#init" title="Effective Go - The Go Programming Language"><code>init()</code></a> 関数同士が依存また干渉するような書き方は避けるべきだろう。</p>
<p><code>main()</code> 関数がキックされるまではメイン以外の <a href="http://golang.org/ref/spec#Go_statements" title="The Go Programming Language Specification - The Go Programming Language">goroutine</a> は(生成は可能だが)起動されないことが保証されているため,記述がスレッドセーフか否か気にする必要はない。
言い方を変えると,何らかの同期を伴う初期化処理の場合はこの方法では記述できないことになる。</p>
<p>「どうしても <code>GetInstance()</code> 関数内で同期をとりたいんじゃ」という場合は… たとえば <a href="https://golang.org/pkg/sync/" title="sync - The Go Programming Language"><code>sync</code></a> パッケージを使うとかだろうか。
Singleton Pattern におあつらえ向きの <a href="https://golang.org/pkg/sync/" title="sync - The Go Programming Language"><code>sync</code></a><code>.Once</code> というのがある。
最初に挙げた例を流用するならこんな感じだろうか。</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-go" data-lang="go"><span class="line"><span class="cl"><span class="c1">//Hello class
</span></span></span><span class="line"><span class="cl"><span class="c1"></span><span class="kd">type</span> <span class="nx">Hello</span> <span class="kd">struct</span><span class="p">{}</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="kd">var</span> <span class="nx">instance</span> <span class="o">*</span> <span class="nx">Hello</span>
</span></span><span class="line hl"><span class="cl"><span class="kd">var</span> <span class="nx">once</span> <span class="nx">sync</span><span class="p">.</span><span class="nx">Once</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="c1">//GetInstance returns singleton instance
</span></span></span><span class="line"><span class="cl"><span class="c1"></span><span class="kd">func</span> <span class="nf">GetInstance</span><span class="p">()</span> <span class="o">*</span> <span class="nx">Hello</span> <span class="p">{</span>
</span></span><span class="line hl"><span class="cl"> <span class="nx">once</span><span class="p">.</span><span class="nf">Do</span><span class="p">(</span><span class="kd">func</span><span class="p">()</span> <span class="p">{</span>
</span></span><span class="line hl"><span class="cl"> <span class="nx">instance</span> <span class="p">=</span> <span class="o">&</span><span class="nx">Hello</span><span class="p">{}</span>
</span></span><span class="line hl"><span class="cl"> <span class="p">})</span>
</span></span><span class="line"><span class="cl"> <span class="k">return</span> <span class="nx">instance</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span></span></span></code></pre></div>
<p>以下のコードで実際に動かして検証してみよう。</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-go" data-lang="go"><span class="line"><span class="cl"><span class="kn">package</span> <span class="nx">main</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="kn">import</span> <span class="p">(</span>
</span></span><span class="line"><span class="cl"> <span class="s">"fmt"</span>
</span></span><span class="line"><span class="cl"> <span class="s">"sync"</span>
</span></span><span class="line"><span class="cl"> <span class="s">"time"</span>
</span></span><span class="line"><span class="cl"><span class="p">)</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="c1">//Hello class
</span></span></span><span class="line"><span class="cl"><span class="c1"></span><span class="kd">type</span> <span class="nx">Hello</span> <span class="kd">struct</span><span class="p">{}</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="kd">func</span> <span class="p">(</span><span class="nx">h</span> <span class="o">*</span> <span class="nx">Hello</span><span class="p">)</span> <span class="nf">String</span><span class="p">()</span> <span class="kt">string</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl"> <span class="k">return</span> <span class="s">"Hello"</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="kd">var</span> <span class="nx">instance</span> <span class="o">*</span> <span class="nx">Hello</span>
</span></span><span class="line hl"><span class="cl"><span class="kd">var</span> <span class="nx">once</span> <span class="nx">sync</span><span class="p">.</span><span class="nx">Once</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="c1">//GetInstance returns singleton instance
</span></span></span><span class="line"><span class="cl"><span class="c1"></span><span class="kd">func</span> <span class="nf">GetInstance</span><span class="p">()</span> <span class="o">*</span> <span class="nx">Hello</span> <span class="p">{</span>
</span></span><span class="line hl"><span class="cl"> <span class="nx">once</span><span class="p">.</span><span class="nf">Do</span><span class="p">(</span><span class="kd">func</span><span class="p">()</span> <span class="p">{</span>
</span></span><span class="line hl"><span class="cl"> <span class="nx">fmt</span><span class="p">.</span><span class="nf">Println</span><span class="p">(</span><span class="s">"new instance"</span><span class="p">)</span>
</span></span><span class="line hl"><span class="cl"> <span class="nx">time</span><span class="p">.</span><span class="nf">Sleep</span><span class="p">(</span><span class="mi">1</span> <span class="o">*</span> <span class="nx">time</span><span class="p">.</span><span class="nx">Second</span><span class="p">)</span> <span class="c1">//delay 1sec
</span></span></span><span class="line hl"><span class="cl"><span class="c1"></span> <span class="nx">instance</span> <span class="p">=</span> <span class="o">&</span><span class="nx">Hello</span><span class="p">{}</span>
</span></span><span class="line hl"><span class="cl"> <span class="p">})</span>
</span></span><span class="line"><span class="cl"> <span class="k">return</span> <span class="nx">instance</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="kd">func</span> <span class="nf">main</span><span class="p">()</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl"> <span class="nx">ch</span> <span class="o">:=</span> <span class="nb">make</span><span class="p">(</span><span class="kd">chan</span> <span class="kd">interface</span><span class="p">{})</span>
</span></span><span class="line"><span class="cl"> <span class="k">go</span> <span class="nf">run</span><span class="p">(</span><span class="nx">ch</span><span class="p">,</span> <span class="s">"Alice"</span><span class="p">)</span>
</span></span><span class="line"><span class="cl"> <span class="k">go</span> <span class="nf">run</span><span class="p">(</span><span class="nx">ch</span><span class="p">,</span> <span class="s">"Bob"</span><span class="p">)</span>
</span></span><span class="line"><span class="cl"> <span class="k">go</span> <span class="nf">run</span><span class="p">(</span><span class="nx">ch</span><span class="p">,</span> <span class="s">"Chris"</span><span class="p">)</span>
</span></span><span class="line"><span class="cl"> <span class="o"><-</span><span class="nx">ch</span>
</span></span><span class="line"><span class="cl"> <span class="o"><-</span><span class="nx">ch</span>
</span></span><span class="line"><span class="cl"> <span class="o"><-</span><span class="nx">ch</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="kd">func</span> <span class="nf">run</span><span class="p">(</span><span class="nx">ch</span> <span class="kd">chan</span><span class="o"><-</span> <span class="kd">interface</span><span class="p">{},</span> <span class="nx">person</span> <span class="kt">string</span><span class="p">)</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl"> <span class="nx">hello</span> <span class="o">:=</span> <span class="nf">GetInstance</span><span class="p">()</span>
</span></span><span class="line"><span class="cl"> <span class="nx">ch</span> <span class="o"><-</span> <span class="nx">hello</span> <span class="c1">//blocking
</span></span></span><span class="line"><span class="cl"><span class="c1"></span> <span class="nx">fmt</span><span class="p">.</span><span class="nf">Println</span><span class="p">(</span><span class="nx">hello</span><span class="p">,</span> <span class="nx">person</span><span class="p">)</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span></span></span></code></pre></div>
<p><a href="https://play.golang.org/p/8ODOeffoyF">実行結果</a>は以下の通り。</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-text" data-lang="text"><span class="line"><span class="cl">new instance
</span></span><span class="line"><span class="cl">Hello Chris
</span></span><span class="line"><span class="cl">Hello Alice
</span></span><span class="line"><span class="cl">Hello Bob
</span></span></code></pre></div><p>ちゃんと singleton として動作していることが分かる。</p>
<h2>ブックマーク</h2>
<ul>
<li><a href="http://ascii.jp/elem/000/001/235/1235262/">GASCII.jp:Goならわかるシステムプログラミング</a>
<ul>
<li><a href="http://ascii.jp/elem/000/001/480/1480872/">ASCII.jp:Go言語と並列処理(2)|Goならわかるシステムプログラミング</a></li>
</ul>
</li>
<li><a href="https://qiita.com/ruiu/items/54f0dbdec0d48082a5b1">Goでスレッド(goroutine)セーフなプログラムを書くために必ず注意しなければいけない点 - Qiita</a></li>
</ul>
<h2>参考図書</h2>
<div class="hreview">
<div class="photo"><a href="https://www.amazon.co.jp/dp/B099928SJD?tag=baldandersinf-22&linkCode=ogi&th=1&psc=1"><img src="https://m.media-amazon.com/images/I/416Stewy0NS._SL160_.jpg" width="123" alt="photo"></a></div>
<dl>
<dt class="item"><a class="fn url" href="https://www.amazon.co.jp/dp/B099928SJD?tag=baldandersinf-22&linkCode=ogi&th=1&psc=1">プログラミング言語Go</a></dt>
<dd>アラン・ドノバン (著), ブライアン・カーニハン (著), 柴田芳樹 (著)</dd>
<dd>丸善出版 2016-06-20 (Release 2021-07-13)</dd>
<dd>Kindle版</dd>
<dd>B099928SJD (ASIN)</dd>
<dd>評価<abbr class="rating fa-sm" title="5"> <i class="fas fa-star"></i> <i class="fas fa-star"></i> <i class="fas fa-star"></i> <i class="fas fa-star"></i> <i class="fas fa-star"></i></abbr></dd>
</dl>
<p class="description">Kindle 版出た! 一部内容が古びてしまったが,この本は Go 言語の教科書と言ってもいいだろう。感想は<a href="https://text.baldanders.info/remark/2016/07/go-programming-language/" >こちら</a>。</p>
<p class="powered-by">reviewed by <a href='#maker' class='reviewer'>Spiegel</a> on <abbr class="dtreviewed" title="2021-05-22">2021-05-22</abbr> (powered by <a href="https://affiliate.amazon.co.jp/assoc_credentials/home">PA-APIv5</a>)</p>
</div> <!-- プログラミング言語Go -->
<div class="hreview">
<div class="photo"><a href="https://www.amazon.co.jp/dp/B00I8AT1EU?tag=baldandersinf-22&linkCode=ogi&th=1&psc=1"><img src="https://m.media-amazon.com/images/I/41GPVATQiZL._SL160_.jpg" width="125" alt="photo"></a></div>
<dl>
<dt class="item"><a class="fn url" href="https://www.amazon.co.jp/dp/B00I8AT1EU?tag=baldandersinf-22&linkCode=ogi&th=1&psc=1">Java言語で学ぶリファクタリング入門</a></dt>
<dd>結城 浩 (著)</dd>
<dd>SBクリエイティブ 2007-01-26 (Release 2014-03-12)</dd>
<dd>Kindle版</dd>
<dd>B00I8AT1EU (ASIN)</dd>
<dd>評価<abbr class="rating fa-sm" title="5"> <i class="fas fa-star"></i> <i class="fas fa-star"></i> <i class="fas fa-star"></i> <i class="fas fa-star"></i> <i class="fas fa-star"></i></abbr></dd>
</dl>
<p class="description">結城浩さんによる「リファクタリング本」の Kindle 版。意外にも Java 以外でも応用できる優れもの。</p>
<p class="powered-by">reviewed by <a href='#maker' class='reviewer'>Spiegel</a> on <abbr class="dtreviewed" title="2018-12-11">2018-12-11</abbr> (powered by <a href="https://affiliate.amazon.co.jp/assoc_credentials/home">PA-APIv5</a>)</p>
</div> <!-- Java言語で学ぶリファクタリング入門 -->
<div class="hreview">
<div class="photo"><a href="https://www.amazon.co.jp/dp/B00I8AT1BS?tag=baldandersinf-22&linkCode=ogi&th=1&psc=1"><img src="https://m.media-amazon.com/images/I/41uoMp5etSL._SL160_.jpg" width="126" alt="photo"></a></div>
<dl>
<dt class="item"><a class="fn url" href="https://www.amazon.co.jp/dp/B00I8AT1BS?tag=baldandersinf-22&linkCode=ogi&th=1&psc=1">増補改訂版 Java言語で学ぶデザインパターン入門 マルチスレッド編</a></dt>
<dd>結城 浩 (著)</dd>
<dd>SBクリエイティブ 2004-06-18 (Release 2014-03-12)</dd>
<dd>Kindle版</dd>
<dd>B00I8AT1BS (ASIN)</dd>
<dd>評価<abbr class="rating fa-sm" title="5"> <i class="fas fa-star"></i> <i class="fas fa-star"></i> <i class="fas fa-star"></i> <i class="fas fa-star"></i> <i class="fas fa-star"></i></abbr></dd>
</dl>
<p class="description">結城浩さんによる通称「デザパタ本」の Kindle 版。意外にも Java 以外でも応用できる優れもの。</p>
<p class="powered-by">reviewed by <a href='#maker' class='reviewer'>Spiegel</a> on <abbr class="dtreviewed" title="2018-12-07">2018-12-07</abbr> (powered by <a href="https://affiliate.amazon.co.jp/assoc_credentials/home">PA-APIv5</a>)</p>
</div> <!-- Java言語で学ぶデザインパターン入門 マルチスレッド編 -->
<div class="footnotes" role="doc-endnotes">
<hr>
<ol>
<li id="fn:1">
<p>HTTP なんかはステートレスでパラレルにやり取りできるため Singleton Pattern は不要。ちなみに <a href="http://golang.org/ref/spec#Go_statements" title="The Go Programming Language Specification - The Go Programming Language">goroutine</a> 間の通信は <a href="http://golang.org/ref/spec#Channel_types" title="The Go Programming Language Specification - The Go Programming Language">channel</a> を使えっちう話です,はい。 <a href="#fnref:1" class="footnote-backref" role="doc-backlink">↩︎</a></p>
</li>
<li id="fn:2">
<p>このコードのパターンは Singleton Pattern を説明するにはよく出来ているしちゃんと動く(ココ重要)が,同期コストが高いため,実際にはあまり使われない。 Java における Singleton Pattern には様々な実装例があるので探してみるといいだろう。ちなみに Java 使いではなくとも結城浩さんの<a href="https://www.amazon.co.jp/exec/obidos/ASIN/B00I8AT1BS/baldandersinf-22/" title="増補改訂版 Java言語で学ぶデザインパターン入門 マルチスレッド編 | 結城 浩 | コンピュータ・IT | Kindleストア | Amazon">デザパタ本</a>は買って読んでおくことを強くお勧めする。 Java 使いの方から見ると古いバージョンで書かれたコードなのが難点だが,紙の本で買うとサンプルコード入りのディスクが付いてくるので若干お得? <a href="#fnref:2" class="footnote-backref" role="doc-backlink">↩︎</a></p>
</li>
<li id="fn:3">
<p>他にもインスタンスのコピー(コピーコンストラクタ等)を暗黙的に許容する言語ではコピーを無効にする措置が必要,とかある。そういう意味じゃ今回私が書いたコードも不完全で,実際には singleton インスタンスを隠蔽するためのラッパークラスが必要になる。ビジネス・ロジックも含めると,実は Singleton の実装ってそう甘くないのよねー <a href="#fnref:3" class="footnote-backref" role="doc-backlink">↩︎</a></p>
</li>
<li id="fn:4">
<p>どうもソースファイルのファイル名が影響するらしい。つまりファイル名を工夫すれば <a href="https://golang.org/doc/effective_go.html#init" title="Effective Go - The Go Programming Language"><code>init()</code></a> 関数の呼び出し順を制御できる,という噂。 <a href="#fnref:4" class="footnote-backref" role="doc-backlink">↩︎</a></p>
</li>
</ol>
</div>
モンテカルロ法による円周率の推定(その2 CLI)
tag:text.Baldanders.info,2016-11-06:/golang/estimate-of-pi-2-cli/
2016-11-06T08:57:37+00:00
2021-08-12T21:22:05+00:00
さっそく推定結果について評価を行いたいところだが,その前に CLI (command-line interface) を整備する。今回は spf13/cobra パッケージを使うことにする。
Spiegel
https://baldanders.info/profile/
<ol>
<li><a href="https://text.baldanders.info/golang/estimate-of-pi/">モンテカルロ法による円周率の推定(その1)</a></li>
<li><a href="https://text.baldanders.info/golang/estimate-of-pi-2-cli/">モンテカルロ法による円周率の推定(その2 CLI)</a> ← イマココ</li>
<li><a href="https://text.baldanders.info/golang/estimate-of-pi-3-gaussian/">モンテカルロ法による円周率の推定(その3 Gaussian)</a></li>
<li><a href="https://text.baldanders.info/golang/estimate-of-pi-4-prng/">モンテカルロ法による円周率の推定(その4 PRNG)</a></li>
</ol>
<h2>コマンドライン・インタフェース</h2>
<p>さっそく推定結果について評価を行いたいところだが,その前に CLI (command-line interface) を整備する。
どういうことかというと,<a href="https://text.baldanders.info/golang/estimate-of-pi/" title="モンテカルロ法による円周率の推定(その1)">前回</a>作った2つの <code>main()</code> 関数の処理</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-go" data-lang="go"><span class="line"><span class="cl"><span class="kn">package</span> <span class="nx">main</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="kn">import</span> <span class="p">(</span>
</span></span><span class="line"><span class="cl"> <span class="s">"fmt"</span>
</span></span><span class="line"><span class="cl"> <span class="s">"math/rand"</span>
</span></span><span class="line"><span class="cl"> <span class="s">"time"</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"> <span class="s">"github.com/spiegel-im-spiegel/pi/gencmplx"</span>
</span></span><span class="line"><span class="cl"><span class="p">)</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="kd">func</span> <span class="nf">main</span><span class="p">()</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl"> <span class="nx">c</span> <span class="o">:=</span> <span class="nx">gencmplx</span><span class="p">.</span><span class="nf">New</span><span class="p">(</span><span class="nx">rand</span><span class="p">.</span><span class="nf">NewSource</span><span class="p">(</span><span class="nx">time</span><span class="p">.</span><span class="nf">Now</span><span class="p">().</span><span class="nf">UnixNano</span><span class="p">()),</span> <span class="nb">int64</span><span class="p">(</span><span class="mi">10000</span><span class="p">))</span>
</span></span><span class="line"><span class="cl"> <span class="k">for</span> <span class="nx">p</span> <span class="o">:=</span> <span class="k">range</span> <span class="nx">c</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl"> <span class="nx">fmt</span><span class="p">.</span><span class="nf">Printf</span><span class="p">(</span><span class="s">"%v\t%v\n"</span><span class="p">,</span> <span class="nb">real</span><span class="p">(</span><span class="nx">p</span><span class="p">),</span> <span class="nb">imag</span><span class="p">(</span><span class="nx">p</span><span class="p">))</span>
</span></span><span class="line"><span class="cl"> <span class="p">}</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span></code></pre></div><div class="highlight"><pre tabindex="0" class="chroma"><code class="language-go" data-lang="go"><span class="line"><span class="cl"><span class="kn">package</span> <span class="nx">main</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="kn">import</span> <span class="p">(</span>
</span></span><span class="line"><span class="cl"> <span class="s">"fmt"</span>
</span></span><span class="line"><span class="cl"> <span class="s">"math/cmplx"</span>
</span></span><span class="line"><span class="cl"> <span class="s">"math/rand"</span>
</span></span><span class="line"><span class="cl"> <span class="s">"time"</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"> <span class="s">"github.com/spiegel-im-spiegel/pi/gencmplx"</span>
</span></span><span class="line"><span class="cl"><span class="p">)</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="kd">func</span> <span class="nf">main</span><span class="p">()</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl"> <span class="nx">c</span> <span class="o">:=</span> <span class="nx">gencmplx</span><span class="p">.</span><span class="nf">New</span><span class="p">(</span><span class="nx">rand</span><span class="p">.</span><span class="nf">NewSource</span><span class="p">(</span><span class="nx">time</span><span class="p">.</span><span class="nf">Now</span><span class="p">().</span><span class="nf">UnixNano</span><span class="p">()),</span> <span class="nb">int64</span><span class="p">(</span><span class="mi">100000</span><span class="p">))</span>
</span></span><span class="line"><span class="cl"> <span class="nx">n</span> <span class="o">:=</span> <span class="nb">int64</span><span class="p">(</span><span class="mi">0</span><span class="p">)</span> <span class="c1">// total
</span></span></span><span class="line"><span class="cl"><span class="c1"></span> <span class="nx">m</span> <span class="o">:=</span> <span class="nb">int64</span><span class="p">(</span><span class="mi">0</span><span class="p">)</span> <span class="c1">// plot in circle
</span></span></span><span class="line"><span class="cl"><span class="c1"></span> <span class="k">for</span> <span class="nx">p</span> <span class="o">:=</span> <span class="k">range</span> <span class="nx">c</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl"> <span class="nx">n</span><span class="o">++</span>
</span></span><span class="line"><span class="cl"> <span class="k">if</span> <span class="nx">cmplx</span><span class="p">.</span><span class="nf">Abs</span><span class="p">(</span><span class="nx">p</span><span class="p">)</span> <span class="o"><=</span> <span class="nb">float64</span><span class="p">(</span><span class="mi">1</span><span class="p">)</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl"> <span class="nx">m</span><span class="o">++</span>
</span></span><span class="line"><span class="cl"> <span class="p">}</span>
</span></span><span class="line"><span class="cl"> <span class="p">}</span>
</span></span><span class="line"><span class="cl"> <span class="nx">fmt</span><span class="p">.</span><span class="nf">Printf</span><span class="p">(</span><span class="s">"n = %v, m = %v, 4m/n = %v\n"</span><span class="p">,</span> <span class="nx">n</span><span class="p">,</span> <span class="nx">m</span><span class="p">,</span> <span class="nb">float64</span><span class="p">(</span><span class="mi">4</span><span class="o">*</span><span class="nx">m</span><span class="p">)</span><span class="o">/</span><span class="nb">float64</span><span class="p">(</span><span class="nx">n</span><span class="p">))</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span></code></pre></div><p>これをひとつの CLI で呼び出せるよう統合してしまおうというわけ。</p>
<p>CLI については以前に解説した。</p>
<ul>
<li><a href="https://text.baldanders.info/golang/cli-and-facade-pattern/">コマンドライン・インタフェースとファサード・パターン</a></li>
</ul>
<p>このときは <a href="https://github.com/mitchellh/cli" title="mitchellh/cli"><code>mitchellh/cli</code></a> を紹介したが,今回は <a href="https://github.com/spf13/cobra" title="spf13/cobra: A Commander for modern Go CLI interactions"><code>spf13/cobra</code></a> を使うことにする。</p>
<h3>spf13/cobra パッケージ</h3>
<p><a href="https://github.com/spf13/cobra" title="spf13/cobra: A Commander for modern Go CLI interactions"><code>spf13/cobra</code></a> パッケージの作者 <a href="https://github.com/spf13">spf13 (Steve Francia)</a> さんは <a href="https://www.linkedin.com/in/stevefrancia" title="Steven Francia | LinkedIn">Docker の中の人</a>で <a href="https://gohugo.io/" title="The world’s fastest framework for building websites | Hugo">Hugo</a> の作者としても有名な方。
もちろん <a href="https://gohugo.io/" title="The world’s fastest framework for building websites | Hugo">Hugo</a> の CLI にも <a href="https://github.com/spf13/cobra" title="spf13/cobra: A Commander for modern Go CLI interactions"><code>spf13/cobra</code></a> が使われている。</p>
<p>さらにありがたいことに <a href="https://github.com/spf13/cobra" title="spf13/cobra: A Commander for modern Go CLI interactions"><code>spf13/cobra</code></a> にはテンプレートコードを出力する CLI も用意されている。
インストールは <code>go get</code> コマンドで行う。</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-text" data-lang="text"><span class="line"><span class="cl">$ go get -v github.com/spf13/cobra/cobra
</span></span></code></pre></div><p>これで <a href="https://github.com/spf13/cobra" title="spf13/cobra: A Commander for modern Go CLI interactions"><code>spf13/cobra</code></a> パッケージ本体と CLI がインストールされる。
テンプレートコードの生成は以下のコマンドを叩く。</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-text" data-lang="text"><span class="line"><span class="cl">$ cobra init github.com/spiegel-im-spiegel/pi
</span></span><span class="line"><span class="cl">Your Cobra application is ready at
</span></span><span class="line"><span class="cl">C:\workspace\pi\src\github.com\spiegel-im-spiegel\pi
</span></span><span class="line"><span class="cl">Give it a try by going there and running `go run main.go`
</span></span><span class="line"><span class="cl">Add commands to it by running `cobra add [cmdname]`
</span></span></code></pre></div><p>既にパッケージ用のフォルダが作られている場合は,そのフォルダまで降りて</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-text" data-lang="text"><span class="line"><span class="cl">$ cobra init .
</span></span><span class="line"><span class="cl">Your Cobra application is ready at
</span></span><span class="line"><span class="cl">C:\workspace\pi\src\github.com\spiegel-im-spiegel\pi
</span></span><span class="line"><span class="cl">Give it a try by going there and running `go run main.go`
</span></span><span class="line"><span class="cl">Add commands to it by running `cobra add [cmdname]`
</span></span></code></pre></div><p>でもよい。</p>
<p>この時点で <code>main.go</code> と <code>cmd/root.go</code> のふたつが生成される。</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-go" data-lang="go"><span class="line"><span class="cl"><span class="c1">// Copyright © 2016 NAME HERE <EMAIL ADDRESS>
</span></span></span><span class="line"><span class="cl"><span class="c1">//
</span></span></span><span class="line"><span class="cl"><span class="c1">// Licensed under the Apache License, Version 2.0 (the "License");
</span></span></span><span class="line"><span class="cl"><span class="c1">// you may not use this file except in compliance with the License.
</span></span></span><span class="line"><span class="cl"><span class="c1">// You may obtain a copy of the License at
</span></span></span><span class="line"><span class="cl"><span class="c1">//
</span></span></span><span class="line"><span class="cl"><span class="c1">// http://www.apache.org/licenses/LICENSE-2.0
</span></span></span><span class="line"><span class="cl"><span class="c1">//
</span></span></span><span class="line"><span class="cl"><span class="c1">// Unless required by applicable law or agreed to in writing, software
</span></span></span><span class="line"><span class="cl"><span class="c1">// distributed under the License is distributed on an "AS IS" BASIS,
</span></span></span><span class="line"><span class="cl"><span class="c1">// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
</span></span></span><span class="line"><span class="cl"><span class="c1">// See the License for the specific language governing permissions and
</span></span></span><span class="line"><span class="cl"><span class="c1">// limitations under the License.
</span></span></span><span class="line"><span class="cl"><span class="c1"></span>
</span></span><span class="line"><span class="cl"><span class="kn">package</span> <span class="nx">main</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="kn">import</span> <span class="s">"github.com/spiegel-im-spiegel/pi/cmd"</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="kd">func</span> <span class="nf">main</span><span class="p">()</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl"> <span class="nx">cmd</span><span class="p">.</span><span class="nf">Execute</span><span class="p">()</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span></code></pre></div><div class="highlight"><pre tabindex="0" class="chroma"><code class="language-go" data-lang="go"><span class="line"><span class="cl"><span class="c1">// Copyright © 2016 NAME HERE <EMAIL ADDRESS>
</span></span></span><span class="line"><span class="cl"><span class="c1">//
</span></span></span><span class="line"><span class="cl"><span class="c1">// Licensed under the Apache License, Version 2.0 (the "License");
</span></span></span><span class="line"><span class="cl"><span class="c1">// you may not use this file except in compliance with the License.
</span></span></span><span class="line"><span class="cl"><span class="c1">// You may obtain a copy of the License at
</span></span></span><span class="line"><span class="cl"><span class="c1">//
</span></span></span><span class="line"><span class="cl"><span class="c1">// http://www.apache.org/licenses/LICENSE-2.0
</span></span></span><span class="line"><span class="cl"><span class="c1">//
</span></span></span><span class="line"><span class="cl"><span class="c1">// Unless required by applicable law or agreed to in writing, software
</span></span></span><span class="line"><span class="cl"><span class="c1">// distributed under the License is distributed on an "AS IS" BASIS,
</span></span></span><span class="line"><span class="cl"><span class="c1">// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
</span></span></span><span class="line"><span class="cl"><span class="c1">// See the License for the specific language governing permissions and
</span></span></span><span class="line"><span class="cl"><span class="c1">// limitations under the License.
</span></span></span><span class="line"><span class="cl"><span class="c1"></span>
</span></span><span class="line"><span class="cl"><span class="kn">package</span> <span class="nx">cmd</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="kn">import</span> <span class="p">(</span>
</span></span><span class="line"><span class="cl"> <span class="s">"fmt"</span>
</span></span><span class="line"><span class="cl"> <span class="s">"os"</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"> <span class="s">"github.com/spf13/cobra"</span>
</span></span><span class="line"><span class="cl"> <span class="s">"github.com/spf13/viper"</span>
</span></span><span class="line"><span class="cl"><span class="p">)</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="kd">var</span> <span class="nx">cfgFile</span> <span class="kt">string</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="c1">// RootCmd represents the base command when called without any subcommands
</span></span></span><span class="line"><span class="cl"><span class="c1"></span><span class="kd">var</span> <span class="nx">RootCmd</span> <span class="p">=</span> <span class="o">&</span><span class="nx">cobra</span><span class="p">.</span><span class="nx">Command</span><span class="p">{</span>
</span></span><span class="line"><span class="cl"> <span class="nx">Use</span><span class="p">:</span> <span class="s">"pi"</span><span class="p">,</span>
</span></span><span class="line"><span class="cl"> <span class="nx">Short</span><span class="p">:</span> <span class="s">"A brief description of your application"</span><span class="p">,</span>
</span></span><span class="line"><span class="cl"> <span class="nx">Long</span><span class="p">:</span> <span class="s">`A longer description that spans multiple lines and likely contains
</span></span></span><span class="line"><span class="cl"><span class="s">examples and usage of using your application. For example:
</span></span></span><span class="line"><span class="cl"><span class="s">
</span></span></span><span class="line"><span class="cl"><span class="s">Cobra is a CLI library for Go that empowers applications.
</span></span></span><span class="line"><span class="cl"><span class="s">This application is a tool to generate the needed files
</span></span></span><span class="line"><span class="cl"><span class="s">to quickly create a Cobra application.`</span><span class="p">,</span>
</span></span><span class="line"><span class="cl"><span class="c1">// Uncomment the following line if your bare application
</span></span></span><span class="line"><span class="cl"><span class="c1">// has an action associated with it:
</span></span></span><span class="line"><span class="cl"><span class="c1">// Run: func(cmd *cobra.Command, args []string) { },
</span></span></span><span class="line"><span class="cl"><span class="c1"></span><span class="p">}</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="c1">// Execute adds all child commands to the root command sets flags appropriately.
</span></span></span><span class="line"><span class="cl"><span class="c1">// This is called by main.main(). It only needs to happen once to the rootCmd.
</span></span></span><span class="line"><span class="cl"><span class="c1"></span><span class="kd">func</span> <span class="nf">Execute</span><span class="p">()</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl"> <span class="k">if</span> <span class="nx">err</span> <span class="o">:=</span> <span class="nx">RootCmd</span><span class="p">.</span><span class="nf">Execute</span><span class="p">();</span> <span class="nx">err</span> <span class="o">!=</span> <span class="kc">nil</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl"> <span class="nx">fmt</span><span class="p">.</span><span class="nf">Println</span><span class="p">(</span><span class="nx">err</span><span class="p">)</span>
</span></span><span class="line"><span class="cl"> <span class="nx">os</span><span class="p">.</span><span class="nf">Exit</span><span class="p">(</span><span class="o">-</span><span class="mi">1</span><span class="p">)</span>
</span></span><span class="line"><span class="cl"> <span class="p">}</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="kd">func</span> <span class="nf">init</span><span class="p">()</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl"> <span class="nx">cobra</span><span class="p">.</span><span class="nf">OnInitialize</span><span class="p">(</span><span class="nx">initConfig</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"> <span class="c1">// Here you will define your flags and configuration settings.
</span></span></span><span class="line"><span class="cl"><span class="c1"></span> <span class="c1">// Cobra supports Persistent Flags, which, if defined here,
</span></span></span><span class="line"><span class="cl"><span class="c1"></span> <span class="c1">// will be global for your application.
</span></span></span><span class="line"><span class="cl"><span class="c1"></span>
</span></span><span class="line"><span class="cl"> <span class="nx">RootCmd</span><span class="p">.</span><span class="nf">PersistentFlags</span><span class="p">().</span><span class="nf">StringVar</span><span class="p">(</span><span class="o">&</span><span class="nx">cfgFile</span><span class="p">,</span> <span class="s">"config"</span><span class="p">,</span> <span class="s">""</span><span class="p">,</span> <span class="s">"config file (default is $HOME/.pi.yaml)"</span><span class="p">)</span>
</span></span><span class="line"><span class="cl"> <span class="c1">// Cobra also supports local flags, which will only run
</span></span></span><span class="line"><span class="cl"><span class="c1"></span> <span class="c1">// when this action is called directly.
</span></span></span><span class="line"><span class="cl"><span class="c1"></span> <span class="nx">RootCmd</span><span class="p">.</span><span class="nf">Flags</span><span class="p">().</span><span class="nf">BoolP</span><span class="p">(</span><span class="s">"toggle"</span><span class="p">,</span> <span class="s">"t"</span><span class="p">,</span> <span class="kc">false</span><span class="p">,</span> <span class="s">"Help message for toggle"</span><span class="p">)</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="c1">// initConfig reads in config file and ENV variables if set.
</span></span></span><span class="line"><span class="cl"><span class="c1"></span><span class="kd">func</span> <span class="nf">initConfig</span><span class="p">()</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl"> <span class="k">if</span> <span class="nx">cfgFile</span> <span class="o">!=</span> <span class="s">""</span> <span class="p">{</span> <span class="c1">// enable ability to specify config file via flag
</span></span></span><span class="line"><span class="cl"><span class="c1"></span> <span class="nx">viper</span><span class="p">.</span><span class="nf">SetConfigFile</span><span class="p">(</span><span class="nx">cfgFile</span><span class="p">)</span>
</span></span><span class="line"><span class="cl"> <span class="p">}</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"> <span class="nx">viper</span><span class="p">.</span><span class="nf">SetConfigName</span><span class="p">(</span><span class="s">".pi"</span><span class="p">)</span> <span class="c1">// name of config file (without extension)
</span></span></span><span class="line"><span class="cl"><span class="c1"></span> <span class="nx">viper</span><span class="p">.</span><span class="nf">AddConfigPath</span><span class="p">(</span><span class="s">"$HOME"</span><span class="p">)</span> <span class="c1">// adding home directory as first search path
</span></span></span><span class="line"><span class="cl"><span class="c1"></span> <span class="nx">viper</span><span class="p">.</span><span class="nf">AutomaticEnv</span><span class="p">()</span> <span class="c1">// read in environment variables that match
</span></span></span><span class="line"><span class="cl"><span class="c1"></span>
</span></span><span class="line"><span class="cl"> <span class="c1">// If a config file is found, read it in.
</span></span></span><span class="line"><span class="cl"><span class="c1"></span> <span class="k">if</span> <span class="nx">err</span> <span class="o">:=</span> <span class="nx">viper</span><span class="p">.</span><span class="nf">ReadInConfig</span><span class="p">();</span> <span class="nx">err</span> <span class="o">==</span> <span class="kc">nil</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl"> <span class="nx">fmt</span><span class="p">.</span><span class="nf">Println</span><span class="p">(</span><span class="s">"Using config file:"</span><span class="p">,</span> <span class="nx">viper</span><span class="p">.</span><span class="nf">ConfigFileUsed</span><span class="p">())</span>
</span></span><span class="line"><span class="cl"> <span class="p">}</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span></code></pre></div><p>この状態でいきなり動かしてみる。</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-text" data-lang="text"><span class="line"><span class="cl">$ go run main.go
</span></span><span class="line"><span class="cl">A longer description that spans multiple lines and likely contains
</span></span><span class="line"><span class="cl">examples and usage of using your application. For example:
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">Cobra is a CLI library for Go that empowers applications.
</span></span><span class="line"><span class="cl">This application is a tool to generate the needed files
</span></span><span class="line"><span class="cl">to quickly create a Cobra application.
</span></span></code></pre></div><p><code>RootCmd</code> で定義した説明が表示されているのがわかると思う。</p>
<p>次にサブコマンドを定義する。
名前は <code>plot</code> と <code>estmt</code> としようか。</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-text" data-lang="text"><span class="line"><span class="cl">$ cobra add plot
</span></span><span class="line"><span class="cl">plot created at C:\workspace\pi\src\github.com\spiegel-im-spiegel\pi\cmd\plot.go
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">$ cobra add estmt
</span></span><span class="line"><span class="cl">estmt created at C:\workspace\pi\src\github.com\spiegel-im-spiegel\pi\cmd\estmt.go
</span></span></code></pre></div><p>これで <code>cmd/plot.go</code> と <code>cmd/estmt.go</code> のふたつが生成された。
<code>cmd/plot.go</code> の中身を見てみよう。</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-go" data-lang="go"><span class="line"><span class="cl"><span class="c1">// Copyright © 2016 NAME HERE <EMAIL ADDRESS>
</span></span></span><span class="line"><span class="cl"><span class="c1">//
</span></span></span><span class="line"><span class="cl"><span class="c1">// Licensed under the Apache License, Version 2.0 (the "License");
</span></span></span><span class="line"><span class="cl"><span class="c1">// you may not use this file except in compliance with the License.
</span></span></span><span class="line"><span class="cl"><span class="c1">// You may obtain a copy of the License at
</span></span></span><span class="line"><span class="cl"><span class="c1">//
</span></span></span><span class="line"><span class="cl"><span class="c1">// http://www.apache.org/licenses/LICENSE-2.0
</span></span></span><span class="line"><span class="cl"><span class="c1">//
</span></span></span><span class="line"><span class="cl"><span class="c1">// Unless required by applicable law or agreed to in writing, software
</span></span></span><span class="line"><span class="cl"><span class="c1">// distributed under the License is distributed on an "AS IS" BASIS,
</span></span></span><span class="line"><span class="cl"><span class="c1">// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
</span></span></span><span class="line"><span class="cl"><span class="c1">// See the License for the specific language governing permissions and
</span></span></span><span class="line"><span class="cl"><span class="c1">// limitations under the License.
</span></span></span><span class="line"><span class="cl"><span class="c1"></span>
</span></span><span class="line"><span class="cl"><span class="kn">package</span> <span class="nx">cmd</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="kn">import</span> <span class="p">(</span>
</span></span><span class="line"><span class="cl"> <span class="s">"fmt"</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"> <span class="s">"github.com/spf13/cobra"</span>
</span></span><span class="line"><span class="cl"><span class="p">)</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="c1">// plotCmd represents the plot command
</span></span></span><span class="line"><span class="cl"><span class="c1"></span><span class="kd">var</span> <span class="nx">plotCmd</span> <span class="p">=</span> <span class="o">&</span><span class="nx">cobra</span><span class="p">.</span><span class="nx">Command</span><span class="p">{</span>
</span></span><span class="line"><span class="cl"> <span class="nx">Use</span><span class="p">:</span> <span class="s">"plot"</span><span class="p">,</span>
</span></span><span class="line"><span class="cl"> <span class="nx">Short</span><span class="p">:</span> <span class="s">"A brief description of your command"</span><span class="p">,</span>
</span></span><span class="line"><span class="cl"> <span class="nx">Long</span><span class="p">:</span> <span class="s">`A longer description that spans multiple lines and likely contains examples
</span></span></span><span class="line"><span class="cl"><span class="s">and usage of using your command. For example:
</span></span></span><span class="line"><span class="cl"><span class="s">
</span></span></span><span class="line"><span class="cl"><span class="s">Cobra is a CLI library for Go that empowers applications.
</span></span></span><span class="line"><span class="cl"><span class="s">This application is a tool to generate the needed files
</span></span></span><span class="line"><span class="cl"><span class="s">to quickly create a Cobra application.`</span><span class="p">,</span>
</span></span><span class="line"><span class="cl"> <span class="nx">Run</span><span class="p">:</span> <span class="kd">func</span><span class="p">(</span><span class="nx">cmd</span> <span class="o">*</span><span class="nx">cobra</span><span class="p">.</span><span class="nx">Command</span><span class="p">,</span> <span class="nx">args</span> <span class="p">[]</span><span class="kt">string</span><span class="p">)</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl"> <span class="c1">// TODO: Work your own magic here
</span></span></span><span class="line"><span class="cl"><span class="c1"></span> <span class="nx">fmt</span><span class="p">.</span><span class="nf">Println</span><span class="p">(</span><span class="s">"plot called"</span><span class="p">)</span>
</span></span><span class="line"><span class="cl"> <span class="p">},</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="kd">func</span> <span class="nf">init</span><span class="p">()</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl"> <span class="nx">RootCmd</span><span class="p">.</span><span class="nf">AddCommand</span><span class="p">(</span><span class="nx">plotCmd</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"> <span class="c1">// Here you will define your flags and configuration settings.
</span></span></span><span class="line"><span class="cl"><span class="c1"></span>
</span></span><span class="line"><span class="cl"> <span class="c1">// Cobra supports Persistent Flags which will work for this command
</span></span></span><span class="line"><span class="cl"><span class="c1"></span> <span class="c1">// and all subcommands, e.g.:
</span></span></span><span class="line"><span class="cl"><span class="c1"></span> <span class="c1">// plotCmd.PersistentFlags().String("foo", "", "A help for foo")
</span></span></span><span class="line"><span class="cl"><span class="c1"></span>
</span></span><span class="line"><span class="cl"> <span class="c1">// Cobra supports local flags which will only run when this command
</span></span></span><span class="line"><span class="cl"><span class="c1"></span> <span class="c1">// is called directly, e.g.:
</span></span></span><span class="line"><span class="cl"><span class="c1"></span> <span class="c1">// plotCmd.Flags().BoolP("toggle", "t", false, "Help message for toggle")
</span></span></span><span class="line"><span class="cl"><span class="c1"></span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span></code></pre></div><p><a href="https://github.com/spf13/cobra" title="spf13/cobra: A Commander for modern Go CLI interactions"><code>spf13/cobra</code></a> パッケージで特徴的なのは,サブコマンドを追加する際に <code>cmd/root.go</code> を変更する必要が無いことである。
サブコマンドの組み込みは <code>cmd</code> パッケージ内の各ファイルに定義されている <code>init()</code> 関数によって <code>main()</code> 起動前に行われる。</p>
<p>この状態で動かしてみよう。</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-text" data-lang="text"><span class="line"><span class="cl">$ go run main.go
</span></span><span class="line"><span class="cl">A longer description that spans multiple lines and likely contains
</span></span><span class="line"><span class="cl">examples and usage of using your application. For example:
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">Cobra is a CLI library for Go that empowers applications.
</span></span><span class="line"><span class="cl">This application is a tool to generate the needed files
</span></span><span class="line"><span class="cl">to quickly create a Cobra application.
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">Usage:
</span></span><span class="line"><span class="cl"> pi [command]
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">Available Commands:
</span></span><span class="line"><span class="cl"> estmt A brief description of your command
</span></span><span class="line"><span class="cl"> plot A brief description of your command
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">Flags:
</span></span><span class="line"><span class="cl"> --config string config file (default is $HOME/.pi.yaml)
</span></span><span class="line"><span class="cl"> -t, --toggle Help message for toggle
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">Use "pi [command] --help" for more information about a command.
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">$ go run main.go plot --help
</span></span><span class="line"><span class="cl">A longer description that spans multiple lines and likely contains examples
</span></span><span class="line"><span class="cl">and usage of using your command. For example:
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">Cobra is a CLI library for Go that empowers applications.
</span></span><span class="line"><span class="cl">This application is a tool to generate the needed files
</span></span><span class="line"><span class="cl">to quickly create a Cobra application.
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">Usage:
</span></span><span class="line"><span class="cl"> pi plot [flags]
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">Global Flags:
</span></span><span class="line"><span class="cl"> --config string config file (default is $HOME/.pi.yaml)
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">$ go run main.go plot
</span></span><span class="line"><span class="cl">plot called
</span></span></code></pre></div><p>問題なくサブコマンドが組み込まれていることがわかる。</p>
<h2>CLI の作成</h2>
<p>では,生成されたテンプレートをベースに機能を組み込んでいく。 …というわけで,出来上がりが以下の repository にある。</p>
<ul>
<li><a href="https://github.com/spiegel-im-spiegel/pi">spiegel-im-spiegel/pi: Estimate of Pi with Monte Carlo method.</a></li>
</ul>
<p>フォルダ構成は以下の通り。</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-text" data-lang="text"><span class="line"><span class="cl">github.com/spiegel-im-spiegel/pi
</span></span><span class="line"><span class="cl">| .editorconfig
</span></span><span class="line"><span class="cl">| .gitignore
</span></span><span class="line"><span class="cl">| glide.lock
</span></span><span class="line"><span class="cl">| glide.yaml
</span></span><span class="line"><span class="cl">| LICENSE
</span></span><span class="line"><span class="cl">| main.go
</span></span><span class="line"><span class="cl">| README.md
</span></span><span class="line"><span class="cl">|
</span></span><span class="line"><span class="cl">+---cmd
</span></span><span class="line"><span class="cl">| estmt.go
</span></span><span class="line"><span class="cl">| plot.go
</span></span><span class="line"><span class="cl">| root.go
</span></span><span class="line"><span class="cl">|
</span></span><span class="line"><span class="cl">+---estmt
</span></span><span class="line"><span class="cl">| estmt.go
</span></span><span class="line"><span class="cl">|
</span></span><span class="line"><span class="cl">+---gencmplx
</span></span><span class="line"><span class="cl">| gencmplx.go
</span></span><span class="line"><span class="cl">|
</span></span><span class="line"><span class="cl">+---genpi
</span></span><span class="line"><span class="cl">| genpi.go
</span></span><span class="line"><span class="cl">|
</span></span><span class="line"><span class="cl">\---plot
</span></span><span class="line"><span class="cl"> plot.go
</span></span></code></pre></div><p>そして各パッケージの構成は以下のようになっている。</p>
<figure style='margin:0 auto;text-align:center;'><a href="./estimate-of-pi.svg"><img src="./estimate-of-pi.svg" srcset="./estimate-of-pi.svg 640w" sizes="(min-width:600px) 500px, 80vw" alt="パッケージ構成" loading="lazy"></a><figcaption><div><a href="./estimate-of-pi.svg">パッケージ構成</a></div></figcaption>
</figure>
<p><a href="https://text.baldanders.info/golang/estimate-of-pi/" title="モンテカルロ法による円周率の推定(その1)">前回</a>と変わったところは <code>genpi</code> パッケージを追加したことだろうか。
こんな感じ。</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-go" data-lang="go"><span class="line"><span class="cl"><span class="kn">package</span> <span class="nx">genpi</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="kn">import</span> <span class="p">(</span>
</span></span><span class="line"><span class="cl"> <span class="s">"math/cmplx"</span>
</span></span><span class="line"><span class="cl"> <span class="s">"math/rand"</span>
</span></span><span class="line"><span class="cl"> <span class="s">"time"</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"> <span class="s">"github.com/spiegel-im-spiegel/pi/gencmplx"</span>
</span></span><span class="line"><span class="cl"><span class="p">)</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="c1">//New returns generator of Pi
</span></span></span><span class="line"><span class="cl"><span class="c1"></span><span class="kd">func</span> <span class="nf">New</span><span class="p">(</span><span class="nx">pc</span><span class="p">,</span> <span class="nx">ec</span> <span class="kt">int64</span><span class="p">)</span> <span class="o"><-</span><span class="kd">chan</span> <span class="kt">float64</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl"> <span class="nx">ch</span> <span class="o">:=</span> <span class="nb">make</span><span class="p">(</span><span class="kd">chan</span> <span class="kt">float64</span><span class="p">)</span>
</span></span><span class="line"><span class="cl"> <span class="nx">pcf</span> <span class="o">:=</span> <span class="nb">float64</span><span class="p">(</span><span class="nx">pc</span><span class="p">)</span>
</span></span><span class="line"><span class="cl"> <span class="k">go</span> <span class="kd">func</span><span class="p">(</span><span class="nx">pc</span><span class="p">,</span> <span class="nx">ec</span> <span class="kt">int64</span><span class="p">)</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl"> <span class="k">for</span> <span class="nx">i</span> <span class="o">:=</span> <span class="nb">int64</span><span class="p">(</span><span class="mi">0</span><span class="p">);</span> <span class="nx">i</span> <span class="p"><</span> <span class="nx">ec</span><span class="p">;</span> <span class="nx">i</span><span class="o">++</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl"> <span class="nx">c</span> <span class="o">:=</span> <span class="nx">gencmplx</span><span class="p">.</span><span class="nf">New</span><span class="p">(</span><span class="nx">rand</span><span class="p">.</span><span class="nf">NewSource</span><span class="p">(</span><span class="nx">time</span><span class="p">.</span><span class="nf">Now</span><span class="p">().</span><span class="nf">UnixNano</span><span class="p">()),</span> <span class="nx">pc</span><span class="p">)</span>
</span></span><span class="line"><span class="cl"> <span class="nx">m</span> <span class="o">:=</span> <span class="nb">int64</span><span class="p">(</span><span class="mi">0</span><span class="p">)</span> <span class="c1">// plot in circle
</span></span></span><span class="line"><span class="cl"><span class="c1"></span> <span class="k">for</span> <span class="nx">p</span> <span class="o">:=</span> <span class="k">range</span> <span class="nx">c</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl"> <span class="k">if</span> <span class="nx">cmplx</span><span class="p">.</span><span class="nf">Abs</span><span class="p">(</span><span class="nx">p</span><span class="p">)</span> <span class="o"><=</span> <span class="nb">float64</span><span class="p">(</span><span class="mi">1</span><span class="p">)</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl"> <span class="nx">m</span><span class="o">++</span>
</span></span><span class="line"><span class="cl"> <span class="p">}</span>
</span></span><span class="line"><span class="cl"> <span class="p">}</span>
</span></span><span class="line"><span class="cl"> <span class="nx">ch</span> <span class="o"><-</span> <span class="nb">float64</span><span class="p">(</span><span class="mi">4</span><span class="o">*</span><span class="nx">m</span><span class="p">)</span> <span class="o">/</span> <span class="nx">pcf</span>
</span></span><span class="line"><span class="cl"> <span class="p">}</span>
</span></span><span class="line"><span class="cl"> <span class="nb">close</span><span class="p">(</span><span class="nx">ch</span><span class="p">)</span>
</span></span><span class="line"><span class="cl"> <span class="p">}(</span><span class="nx">pc</span><span class="p">,</span> <span class="nx">ec</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"> <span class="k">return</span> <span class="nx">ch</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span></code></pre></div><p>指定した回数だけ推定処理を行い,結果を <a href="http://golang.org/ref/spec#Channel_types">channel</a> <code>ch</code> に渡している。
たとえば100,000個の点から円周率を推定する処理を10回したければ</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-text" data-lang="text"><span class="line"><span class="cl">$ go run main.go estmt -e 10 -p 100000
</span></span><span class="line"><span class="cl">3.14576
</span></span><span class="line"><span class="cl">3.1422
</span></span><span class="line"><span class="cl">3.13716
</span></span><span class="line"><span class="cl">3.14648
</span></span><span class="line"><span class="cl">3.14852
</span></span><span class="line"><span class="cl">3.13952
</span></span><span class="line"><span class="cl">3.14824
</span></span><span class="line"><span class="cl">3.13828
</span></span><span class="line"><span class="cl">3.14532
</span></span><span class="line"><span class="cl">3.14312
</span></span></code></pre></div><p>とすればよい。</p>
<p>これでようやく評価のための準備が整った。</p>
<h2>ブックマーク</h2>
<ul>
<li><a href="http://lab.flama.co.jp/archives/1536/">GolangでCLIの場合にcobraを使うことにした件 | FLAMA技術Blog</a></li>
<li><a href="http://qiita.com/astronoka/items/aa2f271d280863cedf5e">packageに複数のinitがあるときの挙動 - Qiita</a></li>
</ul>
<p><a href="https://text.baldanders.info/golang/bookmark/">Go 言語に関するブックマーク集はこちら</a>。</p>
<h2>参考図書</h2>
<div class="hreview">
<div class="photo"><a href="https://www.amazon.co.jp/dp/B099928SJD?tag=baldandersinf-22&linkCode=ogi&th=1&psc=1"><img src="https://m.media-amazon.com/images/I/416Stewy0NS._SL160_.jpg" width="123" alt="photo"></a></div>
<dl>
<dt class="item"><a class="fn url" href="https://www.amazon.co.jp/dp/B099928SJD?tag=baldandersinf-22&linkCode=ogi&th=1&psc=1">プログラミング言語Go</a></dt>
<dd>アラン・ドノバン (著), ブライアン・カーニハン (著), 柴田芳樹 (著)</dd>
<dd>丸善出版 2016-06-20 (Release 2021-07-13)</dd>
<dd>Kindle版</dd>
<dd>B099928SJD (ASIN)</dd>
<dd>評価<abbr class="rating fa-sm" title="5"> <i class="fas fa-star"></i> <i class="fas fa-star"></i> <i class="fas fa-star"></i> <i class="fas fa-star"></i> <i class="fas fa-star"></i></abbr></dd>
</dl>
<p class="description">Kindle 版出た! 一部内容が古びてしまったが,この本は Go 言語の教科書と言ってもいいだろう。感想は<a href="https://text.baldanders.info/remark/2016/07/go-programming-language/" >こちら</a>。</p>
<p class="powered-by">reviewed by <a href='#maker' class='reviewer'>Spiegel</a> on <abbr class="dtreviewed" title="2021-05-22">2021-05-22</abbr> (powered by <a href="https://affiliate.amazon.co.jp/assoc_credentials/home">PA-APIv5</a>)</p>
</div> <!-- プログラミング言語Go -->