スライスはデータの割り当てや解放に責任を持ちません。それはランタイムによって秘匿されています。実は、動的配列を表すフォーマルな型は存在しません。スライスさえあれば十分で、また見ていくとわかるように、データに対してやりたいことを全て理解してくれるように、ランタイムは賢く作られています。動的配列という型が完全には存在しないことに、あなたはほぼ全ての瞬間気づくことはないでしょう。所有権のなさは非常に微かで、気づきにくい特質です。この事実のもう一つの帰結は、長さは配列のプロパティではなく、スライスのプロパティだということです。フィールドは配列の長さではなく、スライスの長さを意味しています。これは言語に新しく触れる人にとって混乱しやすいところでもあります。変えたように見えるかもしれません。出力を見るとわかります)。これは、データは参照として渡されていても、実際のポインタと長さは値で渡されているのが理由です。多くの言語には、すべてのプロパティが参照で渡される配列型があります。データとプロパティを両方参照渡しするか、両方値渡しするかのいずれかです。この問題を修正するには、次の二つの方法が選べます。キーワードを明示することで参照渡しするか、結果のスライスを関数から返して再代入するか、です。スライスはデータを所有しません。後ろの要素は依然としてそこにあり、霧の向こうにある動的配列型によって管理されています。スライスもデータを所有しないという事実は、どのスライスも配列のデータに対する他からの参照がないという仮定をできないことを意味しています。ガベージコレクタの出番です。ガベージコレクタはスライスからまったく参照されなくなった動的配列を片付ける責任を負っています。スライスの使い方が可能になっています。スライスをとって動的配列として使ってそのまま終わっても、メモリをリークしたり、他のスライスをめちゃめちゃにしたり、とにかく配列の生存期間を心配したりする必要はありません。スライスは、スライスの末尾にデータを追加する機能をサポートしています。これは本物の動的配列に非常に近いです。その要素を保持する配列を自動で割り当てます。追加は再割り当てを行いますが、動きます!パフォーマンスが気になる方は、きっと、4個の要素を足したら何が起こるか気になっていることでしょう。スライスに対する主な要求は、効率的であることです。なければプログラマには使われません。この問題を、プログラマには実質的に見えないところでこの問題を解決しています。それが、スライスが本物の動的配列のように見える理由の一つです。ここがランタイムが効率を稼ぐポイントです。バイトです)、それ以上ではページサイズの倍数のブロックを割り当てます。配列を割り当てるときには、要求したよりも大きなサイズのブロックが手に入っていることになります。バイトのブロックが帰ってきます。個分の余裕ができます。防がなければいけないということです。スライスには同じデータを指す他のスライスの情報や、配列のどこ(先頭なのか中間なのか)を指しているのかの情報は持っていない、ということを覚えているでしょうか。(この方法の小さな欠点は、ブロック内で使用可能なスペースが少しだけ小さくなることです。個の整数しか入れることができません。いることを確認します(スライスの先頭は重要ではありません)。その後、新しいデータが余っているスペースに収まるかどうかを確認します。フィールドが新しいデータを含むように更新されます。どれか一つでも失敗すると、新しい配列ブロックが割り当てられ、既存のデータと新しいデータで埋められます。そのブロックを指す他のスライスが存在するなら、何も変わらず同じ場所に残ります。他に参照がなければ、次のガベージコレクションのサイクルが回収します。この仕組みによって、他のスライスを無効化せずにスライスの再割り当てが安全に実行できます。比べると大きな進化です。要素追加をすると、そのデータへの既存の参照(ポインタやイテレータ)は無効になっていました。結果として、要素追加は効率的であるだけではなく、普遍的に手軽です。スライスに要素を足したくなったら、効率や他を壊す心配なく、いつでも足すことができます。あるのかすら心配する必要はありません。追加処理は(メモリが十分にあるという前提の下では)常に成功し、裏方の面倒はランタイムがすべて見てくれます。一つだけ、スライスの要素追加で初心者を、あるいは熟練者でさえも、嵌める落とし穴があります。要素追加の、目に見える非決定的な挙動です。増加が常にバッファを再割り当てさせるとしたらどうでしょう。なく、再割り当てされたバッファだけが上書きされます。これは、同じバッファを使い続けようとしていたり、あるいは元のバッファに値が埋められることを期待していた場合、驚くような結果になってしまいます。埋められたり埋められなかったりするのです。"AAAAAAAAAA";}少し考えてみると、コストのかかる「追加のたびにコピー」セマンティクスを用いない限りはこれは避けられない問題であることに気づきます。データを参照するすべてのスライスを追跡はできず、どこかにはデータを置かなければならないのです。この問題を緩和する方法はいくつかあります:関数の返値をスライスに再代入する。この関数の最重要な結果は返値であり、バッファが使われたか否かではないことに注意して下さい。渡したバッファを再度使うことはしない。元々のスライスを二度と使わないのであれば、それに関して問題を感じることもないでしょう。関数の作者側としては、この手の問題を回避するためにできることはいくつかあります。スライスの元々の範囲にデータを書き込む場合のみです。できる限りこのような処理をする状況を避けることで、非決定性が露わになる可能性を減らすことができます。のちほど、ランタイムがスライスにどう影響するかを予測するためのプロパティについて幾つか議論します。ドキュメントで渡されたスライスがどのように上書きされる/されないかを書き残しておくのは良いアイデアと言えるでしょう。使って確実に渡されたスライスを更新することです。あることがあるので、使えないこともあります。この方法では他のところにある同じデータを指すスライスに関する問題は解決していません。キャッシュスライスへの追加での問題の一つは、この操作は高速ですが十分に高速ではないことです。(GCに対するグローバルなロックをとることなどを抜きにしても)。欲しいのは全体でならして考えると定数時間になる要素追加なのです。データがデフォルトでスレッドローカル記憶域に置かれるという特徴があるため、型システムによって、データがスレッドローカル(ほとんどのデータはそうです)なのか、全スレッドで共有されているのかがわかります。この情報を使うと、スレッドローカルな要素追加にはロックなしでこのメタデータをキャッシュできます。回の直近のメタデータ検索の結果を保持し、スライス追加のできる可能性の高速判定を可能にしています。スライスは興味深い挙動をしめすため、時には、要素追加の際にどのような挙動をするか予測したいことがあります。この目的のために、スライスにはいくつかのプロパティとメソッドが用意されています。要素格納できるように領域を予約する。既存の要素と追加の空き容量の両方を含みます)格納できる余地があれば、何も変化はありません。このメソッドは変更後の容量を返します。あと何要素追加できるかを返すプロパティです。現在のスライスの要素数も含むことにご注意下さい。ランタイムに、スライスへの追加は可能と強制的に教え込みます。フィールドを指定のスライスの終端に合わせる操作です。スライスの要素追加のパフォーマンスがまだどうしても要求するパフォーマンスに届かないときは、さらに別の選択肢があります。型を使うと、ランタイムからのメタデータを参照せずに、配列に最高速でデータを追加できます。(通常のスライスは自分のデータを上書きする出力レンジとしてしか使うことができません)。まとめ熟練プログラマにも初心者プログラマにも、Dの配列とスライスの概念は、配列に対して行いたいほとんど全ての操作を可能にする非常に豊富な機能を提供しています。スライス型は、それの無い他の言語を使い始めるまでは、どれほど素晴らしいものであるが気づきにくい機能の一つとなっています。この記事に対するレビューと提案に感謝します。