List of Function - text.Baldanders.info
tag:text.Baldanders.info,2017-09-23:/tags
2017-09-23T23:32:56+09:00
帰ってきた「しっぽのさきっちょ」
https://text.baldanders.info/images/avatar.jpg
https://text.baldanders.info/images/avatar.jpg
最大公約数と関数型プログラミング
tag:text.Baldanders.info,2017-09-23:/golang/greatest-common-divisor/
2017-09-23T14:32:56+00:00
2021-08-12T21:22:05+00:00
そうだ。最大公約数(greatest common divisor)の話をしよう。
Spiegel
https://baldanders.info/profile/
<ul>
<li><a href="https://qiita.com/rsky/items/a39070208eaea38394c5">配列の全ての要素の最大公約数を求める (Java 8, Python) - Qiita</a></li>
</ul>
<p>この記事を見て思いついた。
そうだ。
最大公約数(greatest common divisor)の話をしよう。</p>
<h2>最大公約数を求める</h2>
<p>まずは定義から。
最大公約数の定義は以下の通り。</p>
<figure>
<blockquote>2つ以上の正の整数に共通な約数(公約数)のうち最大のもの</blockquote></figure>
<p>折角なので何か例題を立ててみよう。</p>
<figure>
<blockquote><p><strong>例題1</strong></p>
<p>20 と 32 の最大公約数を求めよ。</p>
</blockquote></figure>
<p>簡単な数だし,まずは暗算で解いてみる。
それぞれの値を素因数分解すると以下のようになる。</p>
<figure><div class="mathjax">
\begin{align*}
20 &= 2^2 \times 5 \\
32 &= 2^5
\end{align*}
</div></figure>
<p>これにより最大公約数は $2^2 = 4$ だということが分かる。
簡単でよかったね。</p>
<h2>ユークリッドの互除法</h2>
<p>さて,最大公約数を求める機械向けの計算方法としては「<a href="https://ja.wikipedia.org/wiki/%E3%83%A6%E3%83%BC%E3%82%AF%E3%83%AA%E3%83%83%E3%83%89%E3%81%AE%E4%BA%92%E9%99%A4%E6%B3%95" title="ユークリッドの互除法 - Wikipedia">ユークリッドの互除法</a>」が有名である。
具体的な手順は以下の通り。</p>
<ol>
<li>32 を 20 で割った余りは 12</li>
<li>20 を 12 で割った余りは 8</li>
<li>12 を 8 で割った余りは 4</li>
<li>8 を 4 で割った余りは 0</li>
<li>したがって 32 と 20 の最大公約数は 4 である</li>
</ol>
<p>これを図形で表すとこんな感じになる。
(以下の<a href="https://ja.wikipedia.org/wiki/File:GCM_Of_20_And_32.gif" title="File_GCM Of 20 And 32.gif - Wikipedia">図は Wikipedia のもの</a>を拝借した。 <a href="https://creativecommons.org/licenses/by-sa/3.0/" title="Creative Commons — Attribution-ShareAlike 3.0 Unported — CC BY-SA 3.0">CC-BY-SA-3.0</a> で公開されている)</p>
<figure style='margin:0 auto;text-align:center;'><a href="https://ja.wikipedia.org/wiki/File:GCM_Of_20_And_32.gif"><img src="https://upload.wikimedia.org/wikipedia/commons/thumb/1/1a/GCM_Of_20_And_32.gif/640px-GCM_Of_20_And_32.gif" srcset="https://upload.wikimedia.org/wikipedia/commons/thumb/1/1a/GCM_Of_20_And_32.gif/640px-GCM_Of_20_And_32.gif 640w" sizes="(min-width:600px) 500px, 80vw" alt="From Wikipedia" loading="lazy"></a><figcaption><div><a href="https://ja.wikipedia.org/wiki/File:GCM_Of_20_And_32.gif">From Wikipedia</a></div></figcaption>
</figure>
<p>今回は<a href="https://ja.wikipedia.org/wiki/%E3%83%A6%E3%83%BC%E3%82%AF%E3%83%AA%E3%83%83%E3%83%89%E3%81%AE%E4%BA%92%E9%99%A4%E6%B3%95" title="ユークリッドの互除法 - Wikipedia">ユークリッドの互除法</a>の証明は割愛するとして<sup id="fnref:1"><a href="#fn:1" class="footnote-ref" role="doc-noteref">1</a></sup>,上記の手順の 1 から 4 は再帰処理になっていることが分かる。
というわけで,こんな感じのコードを組んでみる。
(だいぶ端折ったコードでゴメン)</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="s">"fmt"</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">gcd</span><span class="p">(</span><span class="nx">a</span><span class="p">,</span> <span class="nx">b</span> <span class="kt">int</span><span class="p">)</span> <span class="kt">int</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl"> <span class="k">if</span> <span class="nx">b</span> <span class="o">==</span> <span class="mi">0</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl"> <span class="k">return</span> <span class="nx">a</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="nf">gcd</span><span class="p">(</span><span class="nx">b</span><span class="p">,</span> <span class="nx">a</span><span class="o">%</span><span class="nx">b</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="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">fmt</span><span class="p">.</span><span class="nf">Println</span><span class="p">(</span><span class="nf">gcd</span><span class="p">(</span><span class="mi">32</span><span class="p">,</span> <span class="mi">20</span><span class="p">))</span> <span class="c1">// 4
</span></span></span><span class="line"><span class="cl"><span class="c1"></span><span class="p">}</span>
</span></span></code></pre></div><p>これで実行結果は 4 になる。</p>
<p>実は <a href="https://golang.org/" title="The Go Programming Language">Go 言語</a>にも最大公約数を求める関数が標準パッケージ <a href="https://golang.org/pkg/math/big/" title="big - The Go Programming Language"><code>math/big</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="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/big"</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">gcd</span><span class="p">(</span><span class="nx">m</span><span class="p">,</span> <span class="nx">n</span> <span class="kt">uint64</span><span class="p">)</span> <span class="kt">uint64</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl"> <span class="nx">x</span> <span class="o">:=</span> <span class="nb">new</span><span class="p">(</span><span class="nx">big</span><span class="p">.</span><span class="nx">Int</span><span class="p">)</span>
</span></span><span class="line"><span class="cl"> <span class="nx">y</span> <span class="o">:=</span> <span class="nb">new</span><span class="p">(</span><span class="nx">big</span><span class="p">.</span><span class="nx">Int</span><span class="p">)</span>
</span></span><span class="line"><span class="cl"> <span class="nx">z</span> <span class="o">:=</span> <span class="nb">new</span><span class="p">(</span><span class="nx">big</span><span class="p">.</span><span class="nx">Int</span><span class="p">)</span>
</span></span><span class="line"><span class="cl"> <span class="nx">a</span> <span class="o">:=</span> <span class="nb">new</span><span class="p">(</span><span class="nx">big</span><span class="p">.</span><span class="nx">Int</span><span class="p">).</span><span class="nf">SetUint64</span><span class="p">(</span><span class="nx">m</span><span class="p">)</span>
</span></span><span class="line"><span class="cl"> <span class="nx">b</span> <span class="o">:=</span> <span class="nb">new</span><span class="p">(</span><span class="nx">big</span><span class="p">.</span><span class="nx">Int</span><span class="p">).</span><span class="nf">SetUint64</span><span class="p">(</span><span class="nx">n</span><span class="p">)</span>
</span></span><span class="line"><span class="cl"> <span class="k">return</span> <span class="nx">z</span><span class="p">.</span><span class="nf">GCD</span><span class="p">(</span><span class="nx">x</span><span class="p">,</span> <span class="nx">y</span><span class="p">,</span> <span class="nx">a</span><span class="p">,</span> <span class="nx">b</span><span class="p">).</span><span class="nf">Uint64</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="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">fmt</span><span class="p">.</span><span class="nf">Println</span><span class="p">(</span><span class="nf">gcd</span><span class="p">(</span><span class="mi">20</span><span class="p">,</span> <span class="mi">32</span><span class="p">))</span> <span class="c1">// 4
</span></span></span><span class="line"><span class="cl"><span class="c1"></span><span class="p">}</span>
</span></span></code></pre></div><p><a href="https://golang.org/pkg/math/big/" title="big - The Go Programming Language"><code>big</code></a><code>.Int.GCD()</code> 関数も<a href="https://ja.wikipedia.org/wiki/%E3%83%A6%E3%83%BC%E3%82%AF%E3%83%AA%E3%83%83%E3%83%89%E3%81%AE%E4%BA%92%E9%99%A4%E6%B3%95" title="ユークリッドの互除法 - Wikipedia">ユークリッドの互除法</a>の一種で,正の整数 $a$, $b$ に対する最大公約数を $\mathrm{gcd}(a, b)$ とすると</p>
<figure style='margin:0 auto;text-align:center;'>
\[
\mathrm{gcd}(a, b) = ax + by
\]
</figure>
<p>となる $x$, $y$ の組み合わせを探すものだ。</p>
<h2>3つ以上の数の最大公約数</h2>
<p>では3つ以上の数の最大公約数を求めるにはどうすればいいか。
ちょっと考えれば分かるが,たとえば $a$, $b$, $c$ の最大公約数を求めたいなら $\mathrm{gcd}(\mathrm{gcd}(a, b), c)$ とすればいい。</p>
<p>では例題を立ててみよう。
これは「<a href="https://qiita.com/rsky/items/a39070208eaea38394c5">配列の全ての要素の最大公約数を求める</a>」の設問と同等と言える。</p>
<figure>
<blockquote><p><strong>例題2</strong></p>
<p>(290021904, 927964716, 826824516, 817140688) の最大公約数を求めよ。</p>
</blockquote></figure>
<p>まずはベタに for 文を回してベタに解いてみる。</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/big"</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">gcd</span><span class="p">(</span><span class="nx">m</span><span class="p">,</span> <span class="nx">n</span> <span class="kt">uint64</span><span class="p">)</span> <span class="kt">uint64</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl"> <span class="nx">x</span> <span class="o">:=</span> <span class="nb">new</span><span class="p">(</span><span class="nx">big</span><span class="p">.</span><span class="nx">Int</span><span class="p">)</span>
</span></span><span class="line"><span class="cl"> <span class="nx">y</span> <span class="o">:=</span> <span class="nb">new</span><span class="p">(</span><span class="nx">big</span><span class="p">.</span><span class="nx">Int</span><span class="p">)</span>
</span></span><span class="line"><span class="cl"> <span class="nx">z</span> <span class="o">:=</span> <span class="nb">new</span><span class="p">(</span><span class="nx">big</span><span class="p">.</span><span class="nx">Int</span><span class="p">)</span>
</span></span><span class="line"><span class="cl"> <span class="nx">a</span> <span class="o">:=</span> <span class="nb">new</span><span class="p">(</span><span class="nx">big</span><span class="p">.</span><span class="nx">Int</span><span class="p">).</span><span class="nf">SetUint64</span><span class="p">(</span><span class="nx">m</span><span class="p">)</span>
</span></span><span class="line"><span class="cl"> <span class="nx">b</span> <span class="o">:=</span> <span class="nb">new</span><span class="p">(</span><span class="nx">big</span><span class="p">.</span><span class="nx">Int</span><span class="p">).</span><span class="nf">SetUint64</span><span class="p">(</span><span class="nx">n</span><span class="p">)</span>
</span></span><span class="line"><span class="cl"> <span class="k">return</span> <span class="nx">z</span><span class="p">.</span><span class="nf">GCD</span><span class="p">(</span><span class="nx">x</span><span class="p">,</span> <span class="nx">y</span><span class="p">,</span> <span class="nx">a</span><span class="p">,</span> <span class="nx">b</span><span class="p">).</span><span class="nf">Uint64</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="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">values</span> <span class="o">:=</span> <span class="p">[]</span><span class="kt">uint64</span><span class="p">{</span><span class="mi">290021904</span><span class="p">,</span> <span class="mi">927964716</span><span class="p">,</span> <span class="mi">826824516</span><span class="p">,</span> <span class="mi">817140688</span><span class="p">}</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"> <span class="nx">z</span> <span class="o">:=</span> <span class="nx">values</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span>
</span></span><span class="line"><span class="cl"> <span class="k">for</span> <span class="nx">_</span><span class="p">,</span> <span class="nx">n</span> <span class="o">:=</span> <span class="k">range</span> <span class="nx">values</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl"> <span class="nx">z</span> <span class="p">=</span> <span class="nf">gcd</span><span class="p">(</span><span class="nx">n</span><span class="p">,</span> <span class="nx">z</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="nx">fmt</span><span class="p">.</span><span class="nf">Println</span><span class="p">(</span><span class="nx">z</span><span class="p">)</span> <span class="c1">// 92
</span></span></span><span class="line"><span class="cl"><span class="c1"></span><span class="p">}</span>
</span></span></code></pre></div><p>ふむふむ。
イケてそうだな<sup id="fnref:2"><a href="#fn:2" class="footnote-ref" role="doc-noteref">2</a></sup>。</p>
<h2>Go で関数型プログラミング</h2>
<p>「<a href="https://qiita.com/rsky/items/a39070208eaea38394c5">配列の全ての要素の最大公約数を求める</a>」で紹介されているコードは高階関数(higher-order function)である <code>reduce()</code> による関数型プログラミングになっている。</p>
<p><a href="https://golang.org/" title="The Go Programming Language">Go 言語</a>の関数は第一級関数(first-class function)なので関数型っぽいプログラミングも可能なのだが<sup id="fnref:3"><a href="#fn:3" class="footnote-ref" role="doc-noteref">3</a></sup>, <code>reduce()</code> のような関数は標準では用意されていない。
ただし,似たような機能を持つパッケージを公開しておられる人はいる。
わざわざ自作するのもナニなので今回は以下のパッケージを利用させてもらおう。</p>
<ul>
<li><a href="https://github.com/robpike/filter">robpike/filter: Simple apply/filter/reduce package.</a></li>
</ul>
<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">"math/big"</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"> <span class="s">"github.com/robpike/filter"</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">gcd</span><span class="p">(</span><span class="nx">m</span><span class="p">,</span> <span class="nx">n</span> <span class="kt">uint64</span><span class="p">)</span> <span class="kt">uint64</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl"> <span class="nx">x</span> <span class="o">:=</span> <span class="nb">new</span><span class="p">(</span><span class="nx">big</span><span class="p">.</span><span class="nx">Int</span><span class="p">)</span>
</span></span><span class="line"><span class="cl"> <span class="nx">y</span> <span class="o">:=</span> <span class="nb">new</span><span class="p">(</span><span class="nx">big</span><span class="p">.</span><span class="nx">Int</span><span class="p">)</span>
</span></span><span class="line"><span class="cl"> <span class="nx">z</span> <span class="o">:=</span> <span class="nb">new</span><span class="p">(</span><span class="nx">big</span><span class="p">.</span><span class="nx">Int</span><span class="p">)</span>
</span></span><span class="line"><span class="cl"> <span class="nx">a</span> <span class="o">:=</span> <span class="nb">new</span><span class="p">(</span><span class="nx">big</span><span class="p">.</span><span class="nx">Int</span><span class="p">).</span><span class="nf">SetUint64</span><span class="p">(</span><span class="nx">m</span><span class="p">)</span>
</span></span><span class="line"><span class="cl"> <span class="nx">b</span> <span class="o">:=</span> <span class="nb">new</span><span class="p">(</span><span class="nx">big</span><span class="p">.</span><span class="nx">Int</span><span class="p">).</span><span class="nf">SetUint64</span><span class="p">(</span><span class="nx">n</span><span class="p">)</span>
</span></span><span class="line"><span class="cl"> <span class="k">return</span> <span class="nx">z</span><span class="p">.</span><span class="nf">GCD</span><span class="p">(</span><span class="nx">x</span><span class="p">,</span> <span class="nx">y</span><span class="p">,</span> <span class="nx">a</span><span class="p">,</span> <span class="nx">b</span><span class="p">).</span><span class="nf">Uint64</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="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">values</span> <span class="o">:=</span> <span class="p">[]</span><span class="kt">uint64</span><span class="p">{</span><span class="mi">290021904</span><span class="p">,</span> <span class="mi">927964716</span><span class="p">,</span> <span class="mi">826824516</span><span class="p">,</span> <span class="mi">817140688</span><span class="p">}</span>
</span></span><span class="line"><span class="cl">
</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">filter</span><span class="p">.</span><span class="nf">Reduce</span><span class="p">(</span><span class="nx">values</span><span class="p">,</span> <span class="nx">gcd</span><span class="p">,</span> <span class="mi">1</span><span class="p">).(</span><span class="kt">uint64</span><span class="p">))</span> <span class="c1">// 92
</span></span></span><span class="line"><span class="cl"><span class="c1"></span><span class="p">}</span>
</span></span></code></pre></div><p>もしくは <code>gcd()</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/big"</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"> <span class="s">"github.com/robpike/filter"</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">values</span> <span class="o">:=</span> <span class="p">[]</span><span class="kt">uint64</span><span class="p">{</span><span class="mi">290021904</span><span class="p">,</span> <span class="mi">927964716</span><span class="p">,</span> <span class="mi">826824516</span><span class="p">,</span> <span class="mi">817140688</span><span class="p">}</span>
</span></span><span class="line"><span class="cl">
</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">filter</span><span class="p">.</span><span class="nf">Reduce</span><span class="p">(</span><span class="nx">values</span><span class="p">,</span>
</span></span><span class="line"><span class="cl"> <span class="kd">func</span><span class="p">(</span><span class="nx">m</span><span class="p">,</span> <span class="nx">n</span> <span class="kt">uint64</span><span class="p">)</span> <span class="kt">uint64</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl"> <span class="nx">x</span> <span class="o">:=</span> <span class="nb">new</span><span class="p">(</span><span class="nx">big</span><span class="p">.</span><span class="nx">Int</span><span class="p">)</span>
</span></span><span class="line"><span class="cl"> <span class="nx">y</span> <span class="o">:=</span> <span class="nb">new</span><span class="p">(</span><span class="nx">big</span><span class="p">.</span><span class="nx">Int</span><span class="p">)</span>
</span></span><span class="line"><span class="cl"> <span class="nx">z</span> <span class="o">:=</span> <span class="nb">new</span><span class="p">(</span><span class="nx">big</span><span class="p">.</span><span class="nx">Int</span><span class="p">)</span>
</span></span><span class="line"><span class="cl"> <span class="nx">a</span> <span class="o">:=</span> <span class="nb">new</span><span class="p">(</span><span class="nx">big</span><span class="p">.</span><span class="nx">Int</span><span class="p">).</span><span class="nf">SetUint64</span><span class="p">(</span><span class="nx">m</span><span class="p">)</span>
</span></span><span class="line"><span class="cl"> <span class="nx">b</span> <span class="o">:=</span> <span class="nb">new</span><span class="p">(</span><span class="nx">big</span><span class="p">.</span><span class="nx">Int</span><span class="p">).</span><span class="nf">SetUint64</span><span class="p">(</span><span class="nx">n</span><span class="p">)</span>
</span></span><span class="line"><span class="cl"> <span class="k">return</span> <span class="nx">z</span><span class="p">.</span><span class="nf">GCD</span><span class="p">(</span><span class="nx">x</span><span class="p">,</span> <span class="nx">y</span><span class="p">,</span> <span class="nx">a</span><span class="p">,</span> <span class="nx">b</span><span class="p">).</span><span class="nf">Uint64</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="mi">1</span><span class="p">).(</span><span class="kt">uint64</span><span class="p">))</span> <span class="c1">// 92
</span></span></span><span class="line"><span class="cl"><span class="c1"></span><span class="p">}</span>
</span></span></code></pre></div><p>としてもよい。
ほら,これなら「実質的にワンライナー」と呼べないこともない(笑)</p>
<p><a href="https://github.com/robpike/filter" title="robpike/filter: Simple apply/filter/reduce package."><code>robpike/filter</code></a> パッケージの作者も書いておられるが</p>
<figure lang="en">
<blockquote>
<q>I wanted to see how hard it was to implement this sort of thing in Go, with as nice an API as I could manage. It wasn't hard.<br>
<br>
Having written it a couple of years ago, I haven't had occasion to use it once. Instead, I just use "for" loops.<br>
<br>
You shouldn't use it either.</q>
</blockquote>
<figcaption><div>via <q><a href="https://github.com/robpike/filter">robpike/filter</a></q></div></figcaption>
</figure>
<p><a href="https://github.com/robpike/filter" title="robpike/filter: Simple apply/filter/reduce package."><code>filter</code></a><code>.Reduce()</code> 関数を駆動するコストを考えれば<sup id="fnref:4"><a href="#fn:4" class="footnote-ref" role="doc-noteref">4</a></sup> 普通に for 文で回したほうが安上がりだよね。
イマドキっぽく関数型言語の利点をいくつか取り込んでいるとはいえ Haskell のようなガッツリした関数型言語とは役割が異なるので,無理に関数型にこだわらなくてもいいということである。</p>
<h2>ブックマーク</h2>
<ul>
<li>
<p><a href="https://qiita.com/tawatawa/items/408b872a7092be0d7b3c">3つ以上の数の最大公約数と最小公倍数 - Qiita</a></p>
</li>
<li>
<p><a href="https://qiita.com/taksatou@github/items/d721a62158f554b8e399">Goで関数型プログラミング - Qiita</a></p>
</li>
<li>
<p><a href="https://qiita.com/yohhoy/items/d3c12361bb5eed3cbede">Go言語では高階関数よりforループを使え(by Rob Pike氏) - Qiita</a></p>
</li>
<li>
<p><a href="https://qiita.com/hiruberuto/items/26a813ab2b188ca39019">関数型言語のウソとホント - Qiita</a></p>
</li>
<li>
<p><a href="https://text.baldanders.info/golang/recursive-call-and-function-table/">再帰呼び出しと関数テーブル</a></p>
</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/B07VPSXF6N?tag=baldandersinf-22&linkCode=ogi&th=1&psc=1"><img src="https://m.media-amazon.com/images/I/51jif840ScL._SL160_.jpg" width="113" alt="photo"></a></div>
<dl>
<dt class="item"><a class="fn url" href="https://www.amazon.co.jp/dp/B07VPSXF6N?tag=baldandersinf-22&linkCode=ogi&th=1&psc=1">改訂2版 みんなのGo言語</a></dt>
<dd>松木 雅幸 (著), mattn (著), 藤原 俊一郎 (著), 中島 大一 (著), 上田 拓也 (著), 牧 大輔 (著), 鈴木 健太 (著)</dd>
<dd>技術評論社 2019-08-01 (Release 2019-08-01)</dd>
<dd>Kindle版</dd>
<dd>B07VPSXF6N (ASIN)</dd>
<dd>評価<abbr class="rating fa-sm" title="4"> <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="far fa-star"></i></abbr></dd>
</dl>
<p class="description">改訂2版の目玉は7章の「データベースの扱い方」が追加されたことだろう。他の章では,大まかな構成は1版と同じだが細かい部分が変わっていて Go 1.12 への言及まであるのには驚いた。</p>
<p class="powered-by">reviewed by <a href='#maker' class='reviewer'>Spiegel</a> on <abbr class="dtreviewed" title="2019-08-12">2019-08-12</abbr> (powered by <a href="https://affiliate.amazon.co.jp/assoc_credentials/home">PA-APIv5</a>)</p>
</div> <!-- 改訂2版 みんなのGo言語 -->
<div class="hreview">
<div class="photo"><a href="https://www.amazon.co.jp/dp/B00L0PDMJ0?tag=baldandersinf-22&linkCode=ogi&th=1&psc=1"><img src="https://m.media-amazon.com/images/I/4186Q-UqrDL._SL160_.jpg" width="111" alt="photo"></a></div>
<dl>
<dt class="item"><a class="fn url" href="https://www.amazon.co.jp/dp/B00L0PDMJ0?tag=baldandersinf-22&linkCode=ogi&th=1&psc=1">数学ガールの秘密ノート/整数で遊ぼう</a></dt>
<dd>結城 浩 (著)</dd>
<dd>SBクリエイティブ 2013-12-17 (Release 2014-07-24)</dd>
<dd>Kindle版</dd>
<dd>B00L0PDMJ0 (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"><a href='https://baldanders.info/blog/000670/'>小中学生にお薦め</a>。小学生高学年くらいならギリで理解可能と思われ。</p>
<p class="powered-by">reviewed by <a href='#maker' class='reviewer'>Spiegel</a> on <abbr class="dtreviewed" title="2014-09-26">2014-09-26</abbr> (powered by <a href="https://affiliate.amazon.co.jp/assoc_credentials/home">PA-APIv5</a>)</p>
</div> <!-- 数学ガールの秘密ノート/整数で遊ぼう -->
<div class="hreview">
<div class="photo"><a href="https://www.amazon.co.jp/dp/B00I8AT1CM?tag=baldandersinf-22&linkCode=ogi&th=1&psc=1"><img src="https://m.media-amazon.com/images/I/41vT2D6sERL._SL160_.jpg" width="113" alt="photo"></a></div>
<dl>
<dt class="item"><a class="fn url" href="https://www.amazon.co.jp/dp/B00I8AT1CM?tag=baldandersinf-22&linkCode=ogi&th=1&psc=1">数学ガール/フェルマーの最終定理</a></dt>
<dd>結城 浩 (著)</dd>
<dd>SBクリエイティブ 2008-07-29 (Release 2014-03-12)</dd>
<dd>Kindle版</dd>
<dd>B00I8AT1CM (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">「フェルマーの最終定理」というサブタイトルをみたとき「なんちう大風呂敷を広げるねん」と思ったものだが,実際に読んでみるとぐいぐい引き込まれる。ひっさびさに頭を使ったような気がする。</p>
<p class="powered-by">reviewed by <a href='#maker' class='reviewer'>Spiegel</a> on <abbr class="dtreviewed" title="2019-01-13">2019-01-13</abbr> (powered by <a href="https://affiliate.amazon.co.jp/assoc_credentials/home">PA-APIv5</a>)</p>
</div> <!-- 数学ガール/フェルマーの最終定理 -->
<div class="footnotes" role="doc-endnotes">
<hr>
<ol>
<li id="fn:1">
<p>結城浩さんが連載しておられる「<a href="https://cakes.mu/series/339" title="数学ガールの秘密ノート|結城浩|cakes(ケイクス)">数学ガールの秘密ノート</a>」に<a href="https://cakes.mu/posts/16292" title="第195回 ユークリッドの互除法(前編)|数学ガールの秘密ノート|結城浩|cakes(ケイクス)">ユークリッドの互除法が出て来る</a>。はやく本にならないかなぁ。 <a href="#fnref:1" class="footnote-backref" role="doc-backlink">↩︎</a></p>
</li>
<li id="fn:2">
<p>繰り返し処理が1回余分に回っているが $gcd(a, a) = a$ で影響はないのでご容赦。 <a href="#fnref:2" class="footnote-backref" role="doc-backlink">↩︎</a></p>
</li>
<li id="fn:3">
<p>あくまでも「ぽい」である。たとえば <a href="https://golang.org/" title="The Go Programming Language">Go 言語</a>では if 文や for 文などは関数でも演算子でもない単なる制御<a href="https://text.baldanders.info/golang/operators-and-statements/" title="演算子とステートメント">構文(stateement)</a>であり,直接ロジックにコンパイルされる。これまでの手続き型言語と関数型言語の利点を合わせたような言語は「マルチパラダイム・プログラミング言語(multiparadigm programming language)」などと呼ばれたりする。 Python や Swift といった近頃流行りの言語もマルチパラダイムの流れのひとつである。 <a href="#fnref:3" class="footnote-backref" role="doc-backlink">↩︎</a></p>
</li>
<li id="fn:4">
<p><a href="https://golang.org/" title="The Go Programming Language">Go 言語</a>には総称型(Generics)がないため <a href="https://github.com/robpike/filter" title="robpike/filter: Simple apply/filter/reduce package."><code>filter</code></a><code>.Reduce()</code> 関数内部で <a href="https://golang.org/pkg/reflect/" title="reflect - The Go Programming Language"><code>reflect</code></a> パッケージを駆使することになるが,その分はどうしてもパフォーマンスに影響を与えてしまう(参考: <a href="https://text.baldanders.info/remark/2017/03/generics-vs-duck-typing/">きみは Generics がとくいなフレンズなんだね,または「制約は構造を生む」</a>)。しかし <a href="https://golang.org/pkg/reflect/" title="reflect - The Go Programming Language"><code>reflect</code></a> パッケージが悪というわけではなく,たとえば<a href="https://text.baldanders.info/golang/sort/" title="ソートを使う">先日紹介</a>した <a href="https://golang.org/pkg/sort/" title="sort - The Go Programming Language"><code>sort</code></a><code>.Slice()</code> 関数は <a href="https://golang.org/pkg/reflect/" title="reflect - The Go Programming Language"><code>reflect</code></a> パッケージを効果的に使用した例といえる。高階関数は見た目はクールだが,それに惑わされることなく目的に適うコードを選ぶことが重要である。とはいえ,勉強のために <a href="https://golang.org/" title="The Go Programming Language">Go 言語</a>で高階関数を組んでみようというのは悪くないと思う。 <a href="#fnref:4" class="footnote-backref" role="doc-backlink">↩︎</a></p>
</li>
</ol>
</div>
関数とポインタ
tag:text.Baldanders.info,2016-03-29:/golang/function-and-pointer/
2016-03-29T13:16:41+00:00
2019-05-18T11:52:31+00:00
Go 言語の引数は基本的に「値渡し(call by value)」である。 Instance の値ではなく実体を渡したいときはポインタを使う。
Spiegel
https://baldanders.info/profile/
<p>いまさらな内容なのだが覚え書きとして記しておく。</p>
<h2>Go 言語における Calling Sequence</h2>
<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="kd">func</span> <span class="nf">add</span><span class="p">(</span><span class="nx">x</span> <span class="kt">int</span><span class="p">,</span> <span class="nx">y</span> <span class="kt">int</span><span class="p">)</span> <span class="kt">int</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl"> <span class="k">return</span> <span class="nx">x</span> <span class="o">+</span> <span class="nx">y</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span></code></pre></div><p><code>add</code> に続く括弧内が引数を定義していて,括弧の後ろの <code>int</code> は返り値の型<sup id="fnref:1"><a href="#fn:1" class="footnote-ref" role="doc-noteref">1</a></sup> を示している。
<code>add()</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="s">"fmt"</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">add</span><span class="p">(</span><span class="nx">x</span> <span class="kt">int</span><span class="p">,</span> <span class="nx">y</span> <span class="kt">int</span><span class="p">)</span> <span class="kt">int</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl"> <span class="k">return</span> <span class="nx">x</span> <span class="o">+</span> <span class="nx">y</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">ans</span> <span class="o">:=</span> <span class="nf">add</span><span class="p">(</span><span class="mi">42</span><span class="p">,</span> <span class="mi">13</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">ans</span><span class="p">)</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span></code></pre></div><p><code>x</code> と <code>y</code> は同じ int 型なので以下のように記述することもできる。</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">func</span> <span class="nf">add</span><span class="p">(</span><span class="nx">x</span><span class="p">,</span> <span class="nx">y</span> <span class="kt">int</span><span class="p">)</span> <span class="kt">int</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl"> <span class="k">return</span> <span class="nx">x</span> <span class="o">+</span> <span class="nx">y</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span></code></pre></div><p>返り値を組(tuple)で定義することもできる。</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">func</span> <span class="nf">split</span><span class="p">(</span><span class="nx">sum</span> <span class="kt">int</span><span class="p">)</span> <span class="p">(</span><span class="kt">int</span><span class="p">,</span> <span class="kt">int</span><span class="p">)</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl"> <span class="nx">x</span> <span class="p">=</span> <span class="nx">sum</span> <span class="o">*</span> <span class="mi">4</span> <span class="o">/</span> <span class="mi">9</span>
</span></span><span class="line"><span class="cl"> <span class="nx">y</span> <span class="p">=</span> <span class="nx">sum</span> <span class="o">-</span> <span class="nx">x</span>
</span></span><span class="line"><span class="cl"> <span class="k">return</span> <span class="nx">x</span><span class="p">,</span> <span class="nx">y</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="kd">func</span> <span class="nf">add</span><span class="p">(</span><span class="nx">x</span><span class="p">,</span> <span class="nx">y</span> <span class="kt">int</span><span class="p">)</span> <span class="p">(</span><span class="nx">ans</span> <span class="kt">int</span><span class="p">)</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl"> <span class="nx">ans</span> <span class="p">=</span> <span class="nx">x</span> <span class="o">+</span> <span class="nx">y</span>
</span></span><span class="line"><span class="cl"> <span class="k">return</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span></code></pre></div><p>最後の <code>return</code> がないとコンパイル・エラーになるので注意。
この書き方は <a href="http://blog.golang.org/defer-panic-and-recover" title="Defer, Panic, and Recover - The Go Blog">defer</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="s">"fmt"</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">err</span> <span class="o">:=</span> <span class="nf">r</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="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="p">}</span> <span class="k">else</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">"Normal End."</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">r</span><span class="p">()</span> <span class="p">(</span><span class="nx">err</span> <span class="kt">error</span><span class="p">)</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl"> <span class="k">defer</span> <span class="kd">func</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">rec</span> <span class="o">:=</span> <span class="nb">recover</span><span class="p">();</span> <span class="nx">rec</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">err</span> <span class="p">=</span> <span class="nx">fmt</span><span class="p">.</span><span class="nf">Errorf</span><span class="p">(</span><span class="s">"Recovered from: %v"</span><span class="p">,</span> <span class="nx">rec</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="nf">f</span><span class="p">()</span>
</span></span><span class="line"><span class="cl"> <span class="nx">err</span> <span class="p">=</span> <span class="kc">nil</span>
</span></span><span class="line"><span class="cl"> <span class="k">return</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">f</span><span class="p">()</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl"> <span class="nb">panic</span><span class="p">(</span><span class="s">"Panic!"</span><span class="p">)</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span></code></pre></div><p>このコード<sup id="fnref:2"><a href="#fn:2" class="footnote-ref" role="doc-noteref">2</a></sup> では <code>r()</code> 関数内で <a href="http://blog.golang.org/defer-panic-and-recover" title="Defer, Panic, and Recover - The Go Blog">panic</a> を捕まえ, 返り値の <code>err</code> に値をセットしなおしている。</p>
<h3>Go 言語の引数は「値渡し」</h3>
<p><a href="https://golang.org/" title="The Go Programming Language">Go 言語</a>の引数は基本的に「値渡し(call by value)」である。
たとえば先程の足し算を</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">func</span> <span class="nf">add</span><span class="p">(</span><span class="nx">x</span><span class="p">,</span> <span class="nx">y</span> <span class="kt">int</span><span class="p">)</span> <span class="kt">int</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl"> <span class="nx">x</span> <span class="o">+=</span> <span class="nx">y</span>
</span></span><span class="line"><span class="cl"> <span class="k">return</span> <span class="nx">x</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="s">"fmt"</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">add</span><span class="p">(</span><span class="nx">x</span><span class="p">,</span> <span class="nx">y</span> <span class="kt">int</span><span class="p">)</span> <span class="kt">int</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl"> <span class="nx">x</span> <span class="o">+=</span> <span class="nx">y</span>
</span></span><span class="line"><span class="cl"> <span class="k">return</span> <span class="nx">x</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">x</span> <span class="o">:=</span> <span class="mi">42</span>
</span></span><span class="line"><span class="cl"> <span class="nx">y</span> <span class="o">:=</span> <span class="mi">13</span>
</span></span><span class="line"><span class="cl"> <span class="nx">ans</span> <span class="o">:=</span> <span class="nf">add</span><span class="p">(</span><span class="nx">x</span><span class="p">,</span> <span class="nx">y</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">"%d + %d = %d\n"</span><span class="p">,</span> <span class="nx">x</span><span class="p">,</span> <span class="nx">y</span><span class="p">,</span> <span class="nx">ans</span><span class="p">)</span> <span class="c1">//output: 42 + 13 = 55
</span></span></span><span class="line"><span class="cl"><span class="c1"></span><span class="p">}</span>
</span></span></code></pre></div><p>呼び出し元で <code>add()</code> 関数の引数に渡した instance は関数実行後も変化しない。
このため引数の値渡しは thread safe なコードに向いている。
ただし関数呼び出し時に instance の値が常にコピーされるため<sup id="fnref:3"><a href="#fn:3" class="footnote-ref" role="doc-noteref">3</a></sup>,サイズの大きな instance の場合は呼び出し時のコストが高くなる。
引数の値渡しが有利な例としては value object を構成する場合などが考えられる。</p>
<p>Instance の値ではなく実体を渡したいときがある。
この場合はポインタを使う。
つまり instance へのポインタ値を渡すのである。</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="s">"fmt"</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">add</span><span class="p">(</span><span class="nx">x</span><span class="p">,</span> <span class="nx">y</span> <span class="o">*</span><span class="kt">int</span><span class="p">)</span> <span class="kt">int</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl"> <span class="o">*</span><span class="nx">x</span> <span class="o">+=</span> <span class="o">*</span><span class="nx">y</span>
</span></span><span class="line"><span class="cl"> <span class="k">return</span> <span class="o">*</span><span class="nx">x</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">x</span> <span class="o">:=</span> <span class="mi">42</span>
</span></span><span class="line"><span class="cl"> <span class="nx">y</span> <span class="o">:=</span> <span class="mi">13</span>
</span></span><span class="line"><span class="cl"> <span class="nx">ans</span> <span class="o">:=</span> <span class="nf">add</span><span class="p">(</span><span class="o">&</span><span class="nx">x</span><span class="p">,</span> <span class="o">&</span><span class="nx">y</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">"%d + %d = %d\n"</span><span class="p">,</span> <span class="nx">x</span><span class="p">,</span> <span class="nx">y</span><span class="p">,</span> <span class="nx">ans</span><span class="p">)</span> <span class="c1">//output: 55 + 13 = 55
</span></span></span><span class="line"><span class="cl"><span class="c1"></span><span class="p">}</span>
</span></span></code></pre></div><p>このコードでは <code>add()</code> 関数実行後の <code>x</code> の値が変更されている。
このように instance へのポインタ値を引数として渡すやり方をこの記事では,通常の「値渡し」とは区別して,「ポインタ渡し」と呼ぶことにする<sup id="fnref:4"><a href="#fn:4" class="footnote-ref" role="doc-noteref">4</a></sup>。</p>
<p>内部状態を持つ instance を引数に指定する場合はポインタ渡しにする必要がある。
しかし引数をポインタ渡しにすると関数実行が thread safe でなくなる可能性がある。
また引数の値が nil の場合も考慮する必要がある。</p>
<p>ちなみに <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="kd">func</span> <span class="nf">add</span><span class="p">(</span><span class="nx">x</span><span class="p">,</span> <span class="nx">y</span> <span class="o">*</span><span class="kt">int</span><span class="p">)</span> <span class="kt">int</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl"> <span class="nx">x</span> <span class="o">+=</span> <span class="nx">y</span>
</span></span><span class="line"><span class="cl"> <span class="k">return</span> <span class="o">*</span><span class="nx">x</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">invalid operation: x += y (operator + not defined on pointer)
</span></span></code></pre></div><p>とコンパイル・エラーになる。
したがって通常は「<a href="https://golang.org/" title="The Go Programming Language">Go 言語</a>のポインタは nullable 参照<sup id="fnref:5"><a href="#fn:5" class="footnote-ref" role="doc-noteref">5</a></sup> と同じ」と考えてよい。</p>
<p>なお,ポインタ演算が必要な場合は <a href="https://golang.org/pkg/unsafe/" title="unsafe - The Go Programming Language"><code>unsafe</code></a> パッケージを使う。</p>
<h3>Slice, Map, Channel は参照渡しのように振る舞う</h3>
<p><a href="http://golang.org/ref/spec#Slice_types">slice</a>, <a href="http://golang.org/ref/spec#Map_types">map</a>, <a href="http://golang.org/ref/spec#Channel_types">channel</a> は組み込み型だが内部状態を持つ<sup id="fnref:6"><a href="#fn:6" class="footnote-ref" role="doc-noteref">6</a></sup>。
これらの型の instance を引数に渡す場合は参照渡しのように振る舞う<sup id="fnref:7"><a href="#fn:7" class="footnote-ref" role="doc-noteref">7</a></sup>。</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="s">"fmt"</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">setItem</span><span class="p">(</span><span class="nx">ary</span> <span class="kd">map</span><span class="p">[</span><span class="kt">int</span><span class="p">]</span><span class="kt">int</span><span class="p">,</span> <span class="nx">index</span><span class="p">,</span> <span class="nx">item</span> <span class="kt">int</span><span class="p">)</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl"> <span class="nx">ary</span><span class="p">[</span><span class="nx">index</span><span class="p">]</span> <span class="p">=</span> <span class="nx">item</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">ary</span> <span class="o">:=</span> <span class="kd">map</span><span class="p">[</span><span class="kt">int</span><span class="p">]</span><span class="kt">int</span><span class="p">{</span><span class="mi">0</span><span class="p">:</span> <span class="mi">0</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">ary</span><span class="p">)</span> <span class="c1">//output: map[0:0]
</span></span></span><span class="line"><span class="cl"><span class="c1"></span> <span class="nf">setItem</span><span class="p">(</span><span class="nx">ary</span><span class="p">,</span> <span class="mi">0</span><span class="p">,</span> <span class="mi">1</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">ary</span><span class="p">)</span> <span class="c1">//output: map[0:1]
</span></span></span><span class="line"><span class="cl"><span class="c1"></span> <span class="nf">setItem</span><span class="p">(</span><span class="nx">ary</span><span class="p">,</span> <span class="mi">10</span><span class="p">,</span> <span class="mi">10</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">ary</span><span class="p">)</span> <span class="c1">//output: map[0:1 10:10]
</span></span></span><span class="line"><span class="cl"><span class="c1"></span><span class="p">}</span>
</span></span></code></pre></div><p>ただし固定の配列や <a href="http://golang.org/ref/spec#String_types">string</a> 型<sup id="fnref:8"><a href="#fn:8" class="footnote-ref" role="doc-noteref">8</a></sup> の instance は「値」として振る舞うため<sup id="fnref:9"><a href="#fn:9" class="footnote-ref" role="doc-noteref">9</a></sup>,引数に指定した場合も値渡しのように振る舞う。
<a href="http://golang.org/ref/spec#Slice_types">slice</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="s">"fmt"</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">setItem</span><span class="p">(</span><span class="nx">ary</span> <span class="p">[</span><span class="mi">4</span><span class="p">]</span><span class="kt">int</span><span class="p">,</span> <span class="nx">index</span><span class="p">,</span> <span class="nx">item</span> <span class="kt">int</span><span class="p">)</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl"> <span class="nx">ary</span><span class="p">[</span><span class="nx">index</span><span class="p">]</span> <span class="p">=</span> <span class="nx">item</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">ary</span> <span class="o">:=</span> <span class="p">[</span><span class="mi">4</span><span class="p">]</span><span class="kt">int</span><span class="p">{</span><span class="mi">0</span><span class="p">,</span> <span class="mi">1</span><span class="p">,</span> <span class="mi">2</span><span class="p">,</span> <span class="mi">3</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">ary</span><span class="p">)</span> <span class="c1">//output: [0 1 2 3]
</span></span></span><span class="line"><span class="cl"><span class="c1"></span> <span class="nf">setItem</span><span class="p">(</span><span class="nx">ary</span><span class="p">,</span> <span class="mi">1</span><span class="p">,</span> <span class="mi">10</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">ary</span><span class="p">)</span> <span class="c1">//output: [0 1 2 3]
</span></span></span><span class="line"><span class="cl"><span class="c1"></span> <span class="nx">ary</span><span class="p">[</span><span class="mi">2</span><span class="p">]</span> <span class="p">=</span> <span class="mi">200</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">ary</span><span class="p">)</span> <span class="c1">//output: [0 1 200 3]
</span></span></span><span class="line"><span class="cl"><span class="c1"></span><span class="p">}</span>
</span></span></code></pre></div><p>固定配列や <a href="http://golang.org/ref/spec#String_types">string</a> 型をポインタ渡しすることはできる。
もっとも <a href="http://golang.org/ref/spec#String_types">string</a> 型の instance は「不変(immutable)」なのでポインタ渡しが必要な局面はほとんど無いと思うが<sup id="fnref:10"><a href="#fn:10" class="footnote-ref" role="doc-noteref">10</a></sup>。</p>
<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="s">"fmt"</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">setItem</span><span class="p">(</span><span class="nx">ary</span> <span class="o">*</span><span class="p">[</span><span class="mi">4</span><span class="p">]</span><span class="kt">int</span><span class="p">,</span> <span class="nx">index</span><span class="p">,</span> <span class="nx">item</span> <span class="kt">int</span><span class="p">)</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl"> <span class="p">(</span><span class="o">*</span><span class="nx">ary</span><span class="p">)[</span><span class="nx">index</span><span class="p">]</span> <span class="p">=</span> <span class="nx">item</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">ary</span> <span class="o">:=</span> <span class="p">[</span><span class="mi">4</span><span class="p">]</span><span class="kt">int</span><span class="p">{</span><span class="mi">0</span><span class="p">,</span> <span class="mi">1</span><span class="p">,</span> <span class="mi">2</span><span class="p">,</span> <span class="mi">3</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">ary</span><span class="p">)</span> <span class="c1">//output: [0 1 2 3]
</span></span></span><span class="line"><span class="cl"><span class="c1"></span> <span class="nf">setItem</span><span class="p">(</span><span class="o">&</span><span class="nx">ary</span><span class="p">,</span> <span class="mi">1</span><span class="p">,</span> <span class="mi">10</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">ary</span><span class="p">)</span> <span class="c1">//output: [0 10 2 3]
</span></span></span><span class="line"><span class="cl"><span class="c1"></span><span class="p">}</span>
</span></span></code></pre></div><p>固定配列は不変ではないが,配列を操作するのであれば固定配列ではなく <a href="http://golang.org/ref/spec#Slice_types">slice</a> のほうが扱いやすい。
たとえば上のコードでは <code>slc := ary[:] </code> といった感じにキャストするか最初から <code>ary := []int{0, 1, 2, 3}</code> と初期化すれば <a href="http://golang.org/ref/spec#Slice_types">slice</a> として扱える。</p>
<h2>Method Receiver</h2>
<p>ある型に関数を関連付ける場合は method receiver を使う。</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">type</span> <span class="nx">Vertex</span> <span class="kd">struct</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl"> <span class="nx">X</span> <span class="kt">int</span>
</span></span><span class="line"><span class="cl"> <span class="nx">Y</span> <span class="kt">int</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="p">(</span><span class="nx">v</span> <span class="nx">Vertex</span><span class="p">)</span> <span class="nf">Add</span><span class="p">(</span><span class="nx">dv</span> <span class="nx">Vertex</span><span class="p">)</span> <span class="nx">Vertex</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl"> <span class="nx">v</span><span class="p">.</span><span class="nx">X</span> <span class="o">+=</span> <span class="nx">dv</span><span class="p">.</span><span class="nx">X</span>
</span></span><span class="line"><span class="cl"> <span class="nx">v</span><span class="p">.</span><span class="nx">Y</span> <span class="o">+=</span> <span class="nx">dv</span><span class="p">.</span><span class="nx">Y</span>
</span></span><span class="line"><span class="cl"> <span class="k">return</span> <span class="nx">v</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span></code></pre></div><p><code>(v Vertex)</code> の部分が method receiver である。
<code>Add()</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="s">"fmt"</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="kd">type</span> <span class="nx">Vertex</span> <span class="kd">struct</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl"> <span class="nx">X</span> <span class="kt">int</span>
</span></span><span class="line"><span class="cl"> <span class="nx">Y</span> <span class="kt">int</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="p">(</span><span class="nx">v</span> <span class="nx">Vertex</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="nx">fmt</span><span class="p">.</span><span class="nf">Sprint</span><span class="p">(</span><span class="s">"X = "</span><span class="p">,</span> <span class="nx">v</span><span class="p">.</span><span class="nx">X</span><span class="p">,</span> <span class="s">", Y = "</span><span class="p">,</span> <span class="nx">v</span><span class="p">.</span><span class="nx">Y</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="kd">func</span> <span class="p">(</span><span class="nx">v</span> <span class="nx">Vertex</span><span class="p">)</span> <span class="nf">Add</span><span class="p">(</span><span class="nx">dv</span> <span class="nx">Vertex</span><span class="p">)</span> <span class="nx">Vertex</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl"> <span class="nx">v</span><span class="p">.</span><span class="nx">X</span> <span class="o">+=</span> <span class="nx">dv</span><span class="p">.</span><span class="nx">X</span>
</span></span><span class="line"><span class="cl"> <span class="nx">v</span><span class="p">.</span><span class="nx">Y</span> <span class="o">+=</span> <span class="nx">dv</span><span class="p">.</span><span class="nx">Y</span>
</span></span><span class="line"><span class="cl"> <span class="k">return</span> <span class="nx">v</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">v</span> <span class="o">:=</span> <span class="nx">Vertex</span><span class="p">{</span><span class="nx">X</span><span class="p">:</span> <span class="mi">1</span><span class="p">,</span> <span class="nx">Y</span><span class="p">:</span> <span class="mi">2</span><span class="p">}</span>
</span></span><span class="line"><span class="cl"> <span class="nx">vv</span> <span class="o">:=</span> <span class="nx">v</span><span class="p">.</span><span class="nf">Add</span><span class="p">(</span><span class="nx">Vertex</span><span class="p">{</span><span class="nx">X</span><span class="p">:</span> <span class="mi">3</span><span class="p">,</span> <span class="nx">Y</span><span class="p">:</span> <span class="mi">4</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">v</span><span class="p">)</span> <span class="c1">//output: X = 1, Y = 2
</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">vv</span><span class="p">)</span> <span class="c1">//output: X = 4, Y = 6
</span></span></span><span class="line"><span class="cl"><span class="c1"></span><span class="p">}</span>
</span></span></code></pre></div><p>関数の calling sequence としては <code>v.Add(dv)</code> と <code>Vertex.Add(v, dv)</code> は等価である。
つまり <code>v</code> は <code>Add()</code> 関数の0番目の引数として振る舞い,値渡しでセットされる。</p>
<p>Method receiver の型をポインタ型にすればポインタ渡しにできる。</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="s">"fmt"</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="kd">type</span> <span class="nx">Vertex</span> <span class="kd">struct</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl"> <span class="nx">X</span> <span class="kt">int</span>
</span></span><span class="line"><span class="cl"> <span class="nx">Y</span> <span class="kt">int</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="p">(</span><span class="nx">v</span> <span class="nx">Vertex</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="nx">fmt</span><span class="p">.</span><span class="nf">Sprint</span><span class="p">(</span><span class="s">"X = "</span><span class="p">,</span> <span class="nx">v</span><span class="p">.</span><span class="nx">X</span><span class="p">,</span> <span class="s">", Y = "</span><span class="p">,</span> <span class="nx">v</span><span class="p">.</span><span class="nx">Y</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 hl"><span class="cl"><span class="kd">func</span> <span class="p">(</span><span class="nx">v</span> <span class="o">*</span> <span class="nx">Vertex</span><span class="p">)</span> <span class="nf">Add</span><span class="p">(</span><span class="nx">dv</span> <span class="nx">Vertex</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">v</span> <span class="o">==</span> <span class="kc">nil</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl"> <span class="k">return</span>
</span></span><span class="line"><span class="cl"> <span class="p">}</span>
</span></span><span class="line"><span class="cl"> <span class="nx">v</span><span class="p">.</span><span class="nx">X</span> <span class="o">+=</span> <span class="nx">dv</span><span class="p">.</span><span class="nx">X</span>
</span></span><span class="line"><span class="cl"> <span class="nx">v</span><span class="p">.</span><span class="nx">Y</span> <span class="o">+=</span> <span class="nx">dv</span><span class="p">.</span><span class="nx">Y</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">v</span> <span class="o">:=</span> <span class="o">&</span><span class="nx">Vertex</span><span class="p">{</span><span class="nx">X</span><span class="p">:</span> <span class="mi">1</span><span class="p">,</span> <span class="nx">Y</span><span class="p">:</span> <span class="mi">2</span><span class="p">}</span>
</span></span><span class="line"><span class="cl"> <span class="nx">v</span><span class="p">.</span><span class="nf">Add</span><span class="p">(</span><span class="nx">Vertex</span><span class="p">{</span><span class="nx">X</span><span class="p">:</span> <span class="mi">3</span><span class="p">,</span> <span class="nx">Y</span><span class="p">:</span> <span class="mi">4</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">v</span><span class="p">)</span> <span class="c1">//output: X = 4, Y = 6
</span></span></span><span class="line"><span class="cl"><span class="c1"></span><span class="p">}</span></span></span></code></pre></div>
<p>この場合も calling sequence としては <code>v.Add(dv)</code> と <code>(*Vertex).Add(v, dv)</code> は等価である。</p>
<h3>Method Receiver の暗黙的変換</h3>
<p>Method receiver を値にした場合,呼び出し元の instance がポインタ型であっても暗黙的にコピーが発生し値渡しに変換される。</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="s">"fmt"</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="kd">type</span> <span class="nx">Vertex</span> <span class="kd">struct</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl"> <span class="nx">X</span> <span class="kt">int</span>
</span></span><span class="line"><span class="cl"> <span class="nx">Y</span> <span class="kt">int</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="p">(</span><span class="nx">v</span> <span class="nx">Vertex</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="nx">fmt</span><span class="p">.</span><span class="nf">Sprint</span><span class="p">(</span><span class="s">"X = "</span><span class="p">,</span> <span class="nx">v</span><span class="p">.</span><span class="nx">X</span><span class="p">,</span> <span class="s">", Y = "</span><span class="p">,</span> <span class="nx">v</span><span class="p">.</span><span class="nx">Y</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="kd">func</span> <span class="p">(</span><span class="nx">v</span> <span class="nx">Vertex</span><span class="p">)</span> <span class="nf">Add</span><span class="p">(</span><span class="nx">dv</span> <span class="nx">Vertex</span><span class="p">)</span> <span class="nx">Vertex</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl"> <span class="nx">v</span><span class="p">.</span><span class="nx">X</span> <span class="o">+=</span> <span class="nx">dv</span><span class="p">.</span><span class="nx">X</span>
</span></span><span class="line"><span class="cl"> <span class="nx">v</span><span class="p">.</span><span class="nx">Y</span> <span class="o">+=</span> <span class="nx">dv</span><span class="p">.</span><span class="nx">Y</span>
</span></span><span class="line"><span class="cl"> <span class="k">return</span> <span class="nx">v</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">v</span> <span class="o">:=</span> <span class="o">&</span><span class="nx">Vertex</span><span class="p">{</span><span class="nx">X</span><span class="p">:</span> <span class="mi">1</span><span class="p">,</span> <span class="nx">Y</span><span class="p">:</span> <span class="mi">2</span><span class="p">}</span> <span class="c1">//pointer
</span></span></span><span class="line"><span class="cl"><span class="c1"></span> <span class="nx">vv</span> <span class="o">:=</span> <span class="nx">v</span><span class="p">.</span><span class="nf">Add</span><span class="p">(</span><span class="nx">Vertex</span><span class="p">{</span><span class="nx">X</span><span class="p">:</span> <span class="mi">3</span><span class="p">,</span> <span class="nx">Y</span><span class="p">:</span> <span class="mi">4</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">v</span><span class="p">)</span> <span class="c1">//output: X = 1, Y = 2
</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">vv</span><span class="p">)</span> <span class="c1">//output: X = 4, Y = 6
</span></span></span><span class="line"><span class="cl"><span class="c1"></span><span class="p">}</span>
</span></span></code></pre></div><p>Method receiver をポインタにした場合も,やはり暗黙的にポインタ渡しに変換される。</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="s">"fmt"</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="kd">type</span> <span class="nx">Vertex</span> <span class="kd">struct</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl"> <span class="nx">X</span> <span class="kt">int</span>
</span></span><span class="line"><span class="cl"> <span class="nx">Y</span> <span class="kt">int</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="p">(</span><span class="nx">v</span> <span class="nx">Vertex</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="nx">fmt</span><span class="p">.</span><span class="nf">Sprint</span><span class="p">(</span><span class="s">"X = "</span><span class="p">,</span> <span class="nx">v</span><span class="p">.</span><span class="nx">X</span><span class="p">,</span> <span class="s">", Y = "</span><span class="p">,</span> <span class="nx">v</span><span class="p">.</span><span class="nx">Y</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="kd">func</span> <span class="p">(</span><span class="nx">v</span> <span class="o">*</span><span class="nx">Vertex</span><span class="p">)</span> <span class="nf">Add</span><span class="p">(</span><span class="nx">dv</span> <span class="nx">Vertex</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">v</span> <span class="o">==</span> <span class="kc">nil</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl"> <span class="k">return</span>
</span></span><span class="line"><span class="cl"> <span class="p">}</span>
</span></span><span class="line"><span class="cl"> <span class="nx">v</span><span class="p">.</span><span class="nx">X</span> <span class="o">+=</span> <span class="nx">dv</span><span class="p">.</span><span class="nx">X</span>
</span></span><span class="line"><span class="cl"> <span class="nx">v</span><span class="p">.</span><span class="nx">Y</span> <span class="o">+=</span> <span class="nx">dv</span><span class="p">.</span><span class="nx">Y</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">v</span> <span class="o">:=</span> <span class="nx">Vertex</span><span class="p">{</span><span class="nx">X</span><span class="p">:</span> <span class="mi">1</span><span class="p">,</span> <span class="nx">Y</span><span class="p">:</span> <span class="mi">2</span><span class="p">}</span> <span class="c1">//not pointer
</span></span></span><span class="line"><span class="cl"><span class="c1"></span> <span class="nx">v</span><span class="p">.</span><span class="nf">Add</span><span class="p">(</span><span class="nx">Vertex</span><span class="p">{</span><span class="nx">X</span><span class="p">:</span> <span class="mi">3</span><span class="p">,</span> <span class="nx">Y</span><span class="p">:</span> <span class="mi">4</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">v</span><span class="p">)</span> <span class="c1">//output: X = 4, Y = 6
</span></span></span><span class="line"><span class="cl"><span class="c1"></span><span class="p">}</span>
</span></span></code></pre></div><h3>Method Receiver の値が nil の場合</h3>
<p>Method receiver の値が nil の場合はどうなるか。
まずは値渡しの場合。</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="s">"fmt"</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="kd">type</span> <span class="nx">Vertex</span> <span class="kd">struct</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl"> <span class="nx">X</span> <span class="kt">int</span>
</span></span><span class="line"><span class="cl"> <span class="nx">Y</span> <span class="kt">int</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="p">(</span><span class="nx">v</span> <span class="nx">Vertex</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="nx">fmt</span><span class="p">.</span><span class="nf">Sprint</span><span class="p">(</span><span class="s">"X = "</span><span class="p">,</span> <span class="nx">v</span><span class="p">.</span><span class="nx">X</span><span class="p">,</span> <span class="s">", Y = "</span><span class="p">,</span> <span class="nx">v</span><span class="p">.</span><span class="nx">Y</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="kd">func</span> <span class="p">(</span><span class="nx">v</span> <span class="nx">Vertex</span><span class="p">)</span> <span class="nf">Add</span><span class="p">(</span><span class="nx">dv</span> <span class="nx">Vertex</span><span class="p">)</span> <span class="nx">Vertex</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl"> <span class="nx">v</span><span class="p">.</span><span class="nx">X</span> <span class="o">+=</span> <span class="nx">dv</span><span class="p">.</span><span class="nx">X</span>
</span></span><span class="line"><span class="cl"> <span class="nx">v</span><span class="p">.</span><span class="nx">Y</span> <span class="o">+=</span> <span class="nx">dv</span><span class="p">.</span><span class="nx">Y</span>
</span></span><span class="line"><span class="cl"> <span class="k">return</span> <span class="nx">v</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">v</span> <span class="o">:=</span> <span class="p">(</span><span class="o">*</span><span class="nx">Vertex</span><span class="p">)(</span><span class="kc">nil</span><span class="p">)</span> <span class="c1">//nil
</span></span></span><span class="line"><span class="cl"><span class="c1"></span> <span class="nx">vv</span> <span class="o">:=</span> <span class="nx">v</span><span class="p">.</span><span class="nf">Add</span><span class="p">(</span><span class="nx">Vertex</span><span class="p">{</span><span class="nx">X</span><span class="p">:</span> <span class="mi">3</span><span class="p">,</span> <span class="nx">Y</span><span class="p">:</span> <span class="mi">4</span><span class="p">})</span> <span class="c1">//panic!
</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">v</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">vv</span><span class="p">)</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span></code></pre></div><p>この場合は <code>Add()</code> 関数呼び出し時に <a href="http://blog.golang.org/defer-panic-and-recover" title="Defer, Panic, and Recover - The Go Blog">panic</a> になる。</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-text" data-lang="text"><span class="line"><span class="cl">panic: runtime error: invalid memory address or nil pointer dereference
</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="s">"fmt"</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="kd">type</span> <span class="nx">Vertex</span> <span class="kd">struct</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl"> <span class="nx">X</span> <span class="kt">int</span>
</span></span><span class="line"><span class="cl"> <span class="nx">Y</span> <span class="kt">int</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="p">(</span><span class="nx">v</span> <span class="nx">Vertex</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="nx">fmt</span><span class="p">.</span><span class="nf">Sprint</span><span class="p">(</span><span class="s">"X = "</span><span class="p">,</span> <span class="nx">v</span><span class="p">.</span><span class="nx">X</span><span class="p">,</span> <span class="s">", Y = "</span><span class="p">,</span> <span class="nx">v</span><span class="p">.</span><span class="nx">Y</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="kd">func</span> <span class="p">(</span><span class="nx">v</span> <span class="o">*</span><span class="nx">Vertex</span><span class="p">)</span> <span class="nf">Add</span><span class="p">(</span><span class="nx">dv</span> <span class="nx">Vertex</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">v</span> <span class="o">==</span> <span class="kc">nil</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl"> <span class="k">return</span>
</span></span><span class="line"><span class="cl"> <span class="p">}</span>
</span></span><span class="line"><span class="cl"> <span class="nx">v</span><span class="p">.</span><span class="nx">X</span> <span class="o">+=</span> <span class="nx">dv</span><span class="p">.</span><span class="nx">X</span>
</span></span><span class="line"><span class="cl"> <span class="nx">v</span><span class="p">.</span><span class="nx">Y</span> <span class="o">+=</span> <span class="nx">dv</span><span class="p">.</span><span class="nx">Y</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">v</span> <span class="o">:=</span> <span class="p">(</span><span class="o">*</span><span class="nx">Vertex</span><span class="p">)(</span><span class="kc">nil</span><span class="p">)</span> <span class="c1">//nil
</span></span></span><span class="line"><span class="cl"><span class="c1"></span> <span class="nx">v</span><span class="p">.</span><span class="nf">Add</span><span class="p">(</span><span class="nx">Vertex</span><span class="p">{</span><span class="nx">X</span><span class="p">:</span> <span class="mi">3</span><span class="p">,</span> <span class="nx">Y</span><span class="p">:</span> <span class="mi">4</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">v</span><span class="p">)</span> <span class="c1">//output: <nil>
</span></span></span><span class="line"><span class="cl"><span class="c1"></span><span class="p">}</span>
</span></span></code></pre></div><p>実は <code>Add()</code> 関数呼び出し時点では <a href="http://blog.golang.org/defer-panic-and-recover" title="Defer, Panic, and Recover - The Go Blog">panic</a> にはならない。
上のコードでは <code>v</code> に nil が渡される。
したがって <code>Add()</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="kd">func</span> <span class="p">(</span><span class="nx">v</span> <span class="o">*</span><span class="nx">Vertex</span><span class="p">)</span> <span class="nf">Add</span><span class="p">(</span><span class="nx">dv</span> <span class="nx">Vertex</span><span class="p">)</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl"> <span class="nx">v</span><span class="p">.</span><span class="nx">X</span> <span class="o">+=</span> <span class="nx">dv</span><span class="p">.</span><span class="nx">X</span> <span class="c1">//panic!
</span></span></span><span class="line"><span class="cl"><span class="c1"></span> <span class="nx">v</span><span class="p">.</span><span class="nx">Y</span> <span class="o">+=</span> <span class="nx">dv</span><span class="p">.</span><span class="nx">Y</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span></code></pre></div><p><code>v</code> 内の要素を参照しようとしたところで <a href="http://blog.golang.org/defer-panic-and-recover" title="Defer, Panic, and Recover - The Go Blog">panic</a> になる。
Method receiver をポインタ渡しにする場合は nil 値に注意する必要がある。</p>
<h2>for-range 構文も値渡し</h2>
<p>余談だが for-range 構文も値渡し(つまりコピーが発生する)ので注意が必要である。
たとえば以下のコードで</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="s">"fmt"</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">ary</span> <span class="o">:=</span> <span class="p">[]</span><span class="kt">int</span><span class="p">{</span><span class="mi">0</span><span class="p">,</span> <span class="mi">1</span><span class="p">,</span> <span class="mi">2</span><span class="p">,</span> <span class="mi">3</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">ary</span><span class="p">)</span> <span class="c1">//output: [0 1 2 3]
</span></span></span><span class="line"><span class="cl"><span class="c1"></span> <span class="k">for</span> <span class="nx">_</span><span class="p">,</span> <span class="nx">item</span> <span class="o">:=</span> <span class="k">range</span> <span class="nx">ary</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl"> <span class="nx">item</span> <span class="o">+=</span> <span class="mi">10</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">Println</span><span class="p">(</span><span class="nx">ary</span><span class="p">)</span> <span class="c1">//output: [0 1 2 3]
</span></span></span><span class="line"><span class="cl"><span class="c1"></span><span class="p">}</span>
</span></span></code></pre></div><p>for-range 構文内の <code>item</code> は <code>ary</code> 内の要素を指すのではなく要素のコピーである。
したがって <code>item</code> を操作しても <code>ary</code> には影響しない。
<code>ary</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="s">"fmt"</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">ary</span> <span class="o">:=</span> <span class="p">[]</span><span class="kt">int</span><span class="p">{</span><span class="mi">0</span><span class="p">,</span> <span class="mi">1</span><span class="p">,</span> <span class="mi">2</span><span class="p">,</span> <span class="mi">3</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">ary</span><span class="p">)</span> <span class="c1">//output: [0 1 2 3]
</span></span></span><span class="line hl"><span class="cl"><span class="c1"></span> <span class="k">for</span> <span class="nx">i</span> <span class="o">:=</span> <span class="mi">0</span><span class="p">;</span> <span class="nx">i</span> <span class="p"><</span> <span class="nb">len</span><span class="p">(</span><span class="nx">ary</span><span class="p">);</span> <span class="nx">i</span><span class="o">++</span> <span class="p">{</span>
</span></span><span class="line hl"><span class="cl"> <span class="nx">ary</span><span class="p">[</span><span class="nx">i</span><span class="p">]</span> <span class="o">+=</span> <span class="mi">10</span>
</span></span><span class="line hl"><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">Println</span><span class="p">(</span><span class="nx">ary</span><span class="p">)</span> <span class="c1">//output: [10 11 12 13]
</span></span></span><span class="line"><span class="cl"><span class="c1"></span><span class="p">}</span></span></span></code></pre></div>
<p>とするしかない。</p>
<h2>ブックマーク</h2>
<ul>
<li><a href="https://skatsuta.github.io/2015/12/29/value-receiver-pointer-receiver/">Go 言語の値レシーバとポインタレシーバ | Step by Step</a></li>
<li><a href="https://mattn.kaoriya.net/software/lang/go/20190516095124.htm">Big Sky :: Go のポインタの躓きやすい点</a></li>
</ul>
<div class="footnotes" role="doc-endnotes">
<hr>
<ol>
<li id="fn:1">
<p>型については「<a href="https://text.baldanders.info/golang/object-oriented-programming/">Go 言語における「オブジェクト」</a>」を参照のこと。 <a href="#fnref:1" class="footnote-backref" role="doc-backlink">↩︎</a></p>
</li>
<li id="fn:2">
<p>このコードについては「<a href="https://text.baldanders.info/golang/error-handling/">エラー・ハンドリングについて</a>」で解説している。ちなみに <a href="http://blog.golang.org/defer-panic-and-recover" title="Defer, Panic, and Recover - The Go Blog">panic</a> を潰して error を返すのはエラー・ハンドリングとしては推奨できない。 <a href="#fnref:2" class="footnote-backref" role="doc-backlink">↩︎</a></p>
</li>
<li id="fn:3">
<p>値がどこにコピーされるかは型によって異なる。 <a href="http://golang.org/ref/spec#String_types">string</a> 以外の基本型は値がスタックに積まれる。 <a href="http://golang.org/ref/spec#String_types">string</a> および基本型以外はヒープ領域に値がコピーされその参照(=ポインタ)がスタックに積まれる。 <a href="#fnref:3" class="footnote-backref" role="doc-backlink">↩︎</a></p>
</li>
<li id="fn:4">
<p>以前は,「値渡し」に対置する言葉として「参照渡し(call by reference)」と書いていたが,最近は「もう参照渡しとは言わせない」とか言う原理主義者がいるそうで,言いがかりに巻き込まれないよう「ポインタ渡し」と言い回しを変えることにした。やれやれ。 <a href="#fnref:4" class="footnote-backref" role="doc-backlink">↩︎</a></p>
</li>
<li id="fn:5">
<p>nullable 参照は「null を許容する参照」くらいの意味。 <a href="https://golang.org/" title="The Go Programming Language">Go 言語</a>なら nil 値。 <a href="https://golang.org/" title="The Go Programming Language">Go 言語</a>は「null 安全(null safty)」ではないので null 参照(=無効な参照)の始末について instance を参照する側が責務を負うことになる。(参考: <a href="https://text.baldanders.info/remark/2016/11/null-safety/">「null 安全」について</a>) <a href="#fnref:5" class="footnote-backref" role="doc-backlink">↩︎</a></p>
</li>
<li id="fn:6">
<p><a href="http://golang.org/ref/spec#Slice_types">slice</a>, <a href="http://golang.org/ref/spec#Map_types">map</a>, <a href="http://golang.org/ref/spec#Channel_types">channel</a> は内部状態を持つため <code>new()</code> 関数ではなく <code>make()</code> 関数を使う。 <a href="#fnref:6" class="footnote-backref" role="doc-backlink">↩︎</a></p>
</li>
<li id="fn:7">
<p>詳しくは「<a href="https://text.baldanders.info/golang/array-and-slice/">配列と Slice</a>」および「<a href="https://text.baldanders.info/golang/map/">Map の話</a>」を参照のこと。 <a href="#fnref:7" class="footnote-backref" role="doc-backlink">↩︎</a></p>
</li>
<li id="fn:8">
<p><a href="http://golang.org/ref/spec#String_types">string</a> 型の実体は <code>[]byte</code> 型である。 <a href="#fnref:8" class="footnote-backref" role="doc-backlink">↩︎</a></p>
</li>
<li id="fn:9">
<p>固定の配列や <a href="http://golang.org/ref/spec#String_types">string</a> 型の instance は nil 値を持たない「non-null 参照」と言える。ちなみに <a href="http://golang.org/ref/spec#String_types">string</a> 型のゼロ値は空文字列である。 <a href="#fnref:9" class="footnote-backref" role="doc-backlink">↩︎</a></p>
</li>
<li id="fn:10">
<p>このような需要としては文字列操作で「NULL 状態」が必要な場合であろう。たとえば DBMS にアクセスする場合は NULL 状態を扱う必要がある。なお <a href="https://golang.org/" title="The Go Programming Language">Go 言語</a>のコア・パッケージには <a href="https://golang.org/pkg/database/sql/" title="sql - The Go Programming Language"><code>database/sql</code></a> があり <code>NullString</code> を使うことにより NULL 状態を扱える。このように NULL 状態を扱う必要がある場合は,直にポインタ操作するのではなく,何らかの value object を用意してカプセル化するほうが安全である。 <a href="#fnref:10" class="footnote-backref" role="doc-backlink">↩︎</a></p>
</li>
</ol>
</div>