codesこの広告は、90日以上更新していないブログに表示しています。こんな記事をみて、別の挙動だけどスライスの内部を理解しきれていなかった頃のことを思い出した。前に謎に思っていた挙動についての話。そっちを書き終わって満足してしまい、本題を忘れていました。この挙動は、先のブログで説明した内容がわかっていないと、なかなか理解できないかも。わかってしまえば簡単ですが。やりたいのは、関数側でスライスを操作したときの呼び出し側での結果。順を追ってみてみます。配列を関数内で変更する関数は値渡しで、配列はそれ自体が値なので、まるっとコピーされます。以下の例は、戻り値で返さないと、呼出側は変化しません。3]}スライスを関数内で変更するスライスは、配列(以下、内部配列という)への参照を持つ構造になっているので、スライスを値渡しして関数内で操作した場合、同じ内部配列を参照しているスライス(つまり同じスライス)にも、変更が反映される。サイズが足らない場合は、内部配列を確保しなおすため、以下は戻り値としてスライスを返さないと、呼び出し側のスライスには変更が反映されない。3]}スライス自体のポインタを渡す方法を使うならこう。余裕があるなら、新しい内部配列は作りなおさず、そのまま末尾に追加する。戻り値は同じスライスらしい。4]}ここまでが前提。余裕があった場合は、内部配列の空き部分にそのまま追加されて、呼び出し側にも反映されるだろうという予想。3]}内部配列には余裕があり、そこに追加されているはず。スライスのアドレスは変わっていないため、間違いなく同じものを表示している。つになっているのに、呼び出し側が更新されていないのはなぜか。したら表示されるようになるか。関数のシグネチャは一切変えず、最後の出力の手前に一行追加するだけで解決できます。良かったら考えてみてください。a[:cap(a)]実際にはスライスをポインタ渡しすれば、それでも解決します。スライスは以下のような構造になっています。参照だから同じ内部配列が見えている。情報は値渡しなので、それが呼び出し側に反映されていないのが原因。これは以下のように更新できます。いう言語仕様になっており、実際は内部配列全体を渡せるということ。同じなので以下のように出力されます。更新されてそれでも済むのですが。意識してチューニングしたプログラムを組むような場合に、もしかしたら役に立つかもしれません。「あるものを正しく使うのにその実装まで理解していなければならないというのは好みではありません。」とした一方で、「Goのような低級言語では、利用者が実装まで知っていなければならないのもある程度仕方ないことかもしれませんが。」と締められていました。Goはリテラルで生成して、append()を使ってるだけならあまり気にしないでいいように作っていて、内部をわかっているなら、make()で生成してcap()を意識するという使いかたもできるという住み分けになってるかなという理解。後者は低レベルのチューニングをやる人にとっては必要だと思うし。ある程度やっていたら内部をわかってないと正しく使えない(ハマる)っていうのは、どの言語でも同じなんじゃないかなとも思う。#nextwebconf月別アーカイブリンクhttps://jxck.iohttps://github.com/jxckhttps://twitter.com/jxck_http://mozaic.fmはてなブログをはじめよう!Jxckさんは、はてなブログを使っています。ブログを報告するスターをつけました引用をストックしましたストック一覧を見る閉じる引用するにはまずログインしてくださいログイン閉じる引用をストックできませんでした。再度お試しください閉じる限定公開記事のため引用できません。