[翻蚳]配列、スラむスおよび文字列「挿入」メカニズム

゚ントリヌ


手続き型プログラミング蚀語の最も䞀般的な機胜の1぀は、配列の抂念です。 配列は単玔に芋えるかもしれたせんが、䞀方で、蚀語に远加する前に、次のようないく぀かの問題を解決する必芁がありたす。

これらの質問に察する答えは、配列を蚀語の単玔な機胜ずしお、たたはその蚭蚈の䞻芁郚分ずしお定矩したす。

Goの初期の頃、これらの質問に察する答えを芋぀けるには、抂念が適切ず思われるようになるたでに䜕幎もの議論が必芁でした。 重芁なステップは、柔軟で拡匵可胜なデヌタ構造を䜜成するために、固定サむズの配列に基づくスラむスの抂念を䜜成するこずでした。 ただし、Goの新参者の倚くは、おそらく他の蚀語での経隓がその足跡を残したために、スラむスの原則に぀たずきたす。

この出版物では、これらすべおの誀解を払拭しようずしたす。 これは、 append関数がどのように機胜するのか、それがなぜそのように機胜するのか、それ以倖には䜕も機胜しないのかを説明する郚分で実珟したす。

配列


配列はGo蚀語の重芁な郚分ですが、建物の基瀎のように、より目に芋える郚分の䞋に隠されおいたす。 より興味深く、匷力で、泚目に倀するスラむシング機胜に進む前に、最新の状態にする必芁がありたす。

Goのプログラムでは、配列の皮類にサむズが含たれるため、䜿甚が制限されるため、配列はあたり芋られたせん。

たずえば、広告
var buffer [256]byte 

256バむトを含むバッファヌ倉数を䜜成したす。 バッファヌ倉数タむプにはサむズが含たれ、 [256] byteのようになりたす 。 512バむトの配列は、タむプ[512] byteになりたす 。

配列に関連付けられおいるデヌタは、単なる芁玠の配列です。 抂略的に、メモリ内のバッファは次のようになりたす。
 buffer: byte byte byte ... 256 times ... byte byte byte 

぀たり、倉数には256バむトのデヌタだけが含たれたす。 通垞のむンデックス構文バッファ[0] 、 バッファ[1]などを䜿甚しおバッファ[255]に芁玠にアクセスできたす 0〜255のむンデックスは256芁玠をカバヌしたす。 この範囲を超えようずするず、プログラムがクラッシュしたす。

組み蟌みのlen関数があり、配列、スラむス、その他の型の芁玠数を返したす。 明らかに、配列に察しおlenを正確に返すもの。 この堎合、 lenバッファは256を返したす。

アレむの堎合、アプリケヌションの堎所を芋぀けるこずができたす。 たずえば、マトリックスの倉換には適しおいたすが、Goでの最も䞀般的な甚途はスラむスの保存です。

スラむススラむスヘッダヌ


面癜いこずが起こるスラむスですが、䜿甚を開始する前に、その必芁性ず䜕をしおいるのかを理解する必芁がありたす。

スラむスは、配列の耇数のパヌティションを蚘述するデヌタ構造であり、倉数ずは別に保存されたす。 スラむスは配列ではありたせん 。 スラむスは、配列の䞀郚を衚したす。

前のセクションのバッファヌ配列を䜿甚する堎合、配列をスラむスするこずにより、100から150正確には100から149たでの芁玠を蚘述するスラむスを䜜成できたす。
 var slice []byte = buffer[100:150] 

このコヌドでは、正確には、完党な倉数宣蚀を䜿甚したした。 スラむス倉数のタむプは[] byteで 、「バむトのスラむス」ずしお読み取られ、芁玠100包括的から150排他的にスラむスするこずによりバッファ配列から䜜成されたす。 より「暙準的な」構文では、初期化プロセス䞭に定矩される型を省略したす。
 var slice = buffer[100:150] 

そしお、関数内では、短い圢匏の宣蚀を䜿甚したす。
 slice := buffer[100:150] 

スラむスずは䜕ですか これは完党な説明ではありたせんが、今埌はスラむスを、長さず配列芁玠ぞのポむンタずいう2぀の芁玠で構成される小さな構造ず考えおください。 これを舞台裏で次のようなものず考えおください。
 type sliceHeader struct { Length int ZerothElement *byte } slice := sliceHeader{ Length: 50, ZerothElement: &buffer[100], } 

もちろん、これは単なる䟋です。 これにもかかわらず、この䟋からは、 sliceHeader構造䜓はプログラマヌにアクセスできず、ポむンタヌのタむプは芁玠のタむプに䟝存したすが、スラむスの仕組みの基本的な考え方を理解するこずができたす。

これたで、配列をスラむスする操䜜を䜿甚したしたが、スラむスをスラむスするこずもできたす。
 slice2 := slice[5:10] 


前ず同じ方法で、この操䜜は新しいスラむスを䜜成したすが、この堎合は元のスラむスに関連する芁玠5〜9䞡端を含むから䜜成されたす。 slice2倉数の基本的なsliceHeader構造は次のようになりたす。
 slice2 := sliceHeader{ Length: 5, ZerothElement: &buffer[105], } 

ヘッダヌは、 バッファ倉数にある基になる配列を指すこずに泚意しおください。

再床カットするこずもできたす。これは、スラむスをカットし、カットされたスラむスの構造に結果を保存するこずを意味したす。 ぀たり 埌
 slice = slice[5:10] 

スラむス倉数のsliceHeader構造は、 slice2倉数の堎合ず同じように芋えたす。 たずえば、スラむスをカットするなど、オヌバヌシュヌトが頻繁に発生したす。 この䟋では、スラむスの最初ず最埌の芁玠が省略されたす。
 slice = slice[1:len(slice)-1] 

倚くの堎合、経隓豊富なGoプログラマヌから「スラむスヘッダヌ」に぀いお聞くこずができたす。 これは、スラむス倉数に栌玍されるものです。 たずえば、 bytes.IndexRuneなど、スラむスを匕数ずしお取る関数を呌び出すず、ヘッダヌが関数に枡されたす。 この䟋では
 slashPos := bytes.IndexRune(slice, '/') 

スラむス匕数はIndexRune関数に枡されたす。実際、これは単なる「スラむスヘッダヌ」です。

「スラむスヘッダヌ」には、以䞋で説明する別のデヌタ芁玠がありたすが、最初に、スラむサヌを䜿甚するプログラムを䜜成するずきの「スラむスヘッダヌ」の意味を芋おみたしょう。

スラむスを関数に枡す


スラむスにポむンタヌが含たれおいおも、それ自䜓が倀であるこずを理解するこずが非垞に重芁です。 内郚では、これはポむンタヌず長さを含む構造です。 これは構造䜓ぞのポむンタではありたせん 。

これは重芁です。

前の䟋でIndexRuneを呌び出すず、 「ヘッダヌの䞊郚」のコピヌが 取埗されたす。 この動䜜は重芁な結果をもたらしたす。

簡単な関数を考えおみたしょう
 func AddOneToEachElement(slice []byte) { for i := range slice { slice[i]++ } } 

圌女はタむトルに曞かれおいるこずを正確に行いたす。  for rangeルヌプを䜿甚しお すべおのスラむス芁玠をトラバヌスし、芁玠を増やしたす。

詊しおください
 func main() { slice := buffer[10:20] for i := 0; i < len(slice); i++ { slice[i] = byte(i) } fmt.Println("before", slice) AddOneToEachElement(slice) fmt.Println("after", slice) } 

「 スラむスヘッダヌ 」は関数に枡されたすが、配列の芁玠ぞのポむンタヌが含たれおいるため、元のスラむスヘッダヌずそのコピヌは同じ配列を衚したす。 その結果、関数が終了するず、倉曎された芁玠を元のスラむスから芋るこずができたす。

関数ぞの匕数は実際にはコピヌであり、この䟋はこれを瀺しおいたす。
 func SubtractOneFromLength(slice []byte) []byte { slice = slice[0 : len(slice)-1] return slice } func main() { fmt.Println("Before: len(slice) =", len(slice)) newSlice := SubtractOneFromLength(slice) fmt.Println("After: len(slice) =", len(slice)) fmt.Println("After: len(newSlice) =", len(newSlice)) } 

ここでは、関数では匕数の内容を倉曎できたすが、 タむトルでは倉曎できないこずがわかりたす。 長さはスラむス倉数に栌玍され、関数を呌び出しおも倉曎されたせん。これは、スラむスヘッダヌのコピヌが元のものではなく関数に枡されるためです。 したがっお、タむトルを倉曎する関数を䜜成する堎合は、䟋で行ったように、それを返す必芁がありたす。 スラむス倉数は倉曎されたせんが、戻り倀には新しい長さがあり、これはnewSliceに栌玍されたす 。

スラむサヌポむンタヌ生産方法


スラむスヘッダヌを倉曎する関数を蚘述する別の方法がありたす。これは、スラむスぞのポむンタヌを関数に枡すこずです。 この機胜を瀺すための䟋のバリ゚ヌションを次に瀺したす。
 func PtrSubtractOneFromLength(slicePtr *[]byte) { slice := *slicePtr *slicePtr = slice[0 : len(slice)-1] } func main() { fmt.Println("Before: len(slice) =", len(slice)) PtrSubtractOneFromLength(&slice) fmt.Println("After: len(slice) =", len(slice)) } 

抜象化のレベル䞀時倉数が䜙分であるため、䟋は少し厄介に思えるかもしれたせんが、スラむスぞのポむンタヌを䜿甚する堎合が1぀ありたす。 スラむスを倉曎するメ゜ッドを蚘述するずき、レシヌバヌずしおポむンタヌを䜿甚するのが慣䟋です。

最埌のスラッシュを削陀する方法が必芁だずしたしょう。 次のように蚘述できたす。
 type path []byte func (p *path) TruncateAtFinalSlash() { i := bytes.LastIndex(*p, []byte("/")) if i >= 0 { *p = (*p)[0:i] } } func main() { pathName := path("/usr/bin/tso") //     path pathName.TruncateAtFinalSlash() fmt.Printf("%s\n", pathName) } 

この䟋を実行するず、必芁なこずが起こるこずがわかりたす。぀たり、メ゜ッドがスラむスを倉曎したす。

䞀方、ASCII文字の倧文字を蚭定するパスのメ゜ッドを䜜成する堎合英語の文字で動䜜が定矩されおいない堎合、レシヌバヌの倀は必芁な配列を指すため、メ゜ッドはポむンタヌではなく倀を操䜜できたす。
 type path []byte func (p path) ToUpper() { for i, b := range p { if 'a' <= b && b <= 'z' { p[i] = b + 'A' - 'a' } } } func main() { pathName := path("/usr/bin/tso") pathName.ToUpper() fmt.Printf("%s\n", pathName) } 

ここで、 ToUpperメ゜ッドは、芁玠のむンデックスを䜿甚するためにfor範囲で2぀の倉数を䜿甚し、スラむス芁玠自䜓を盎接䜿甚したす。 これにより、 p [i]ぞの再曞き蟌みが回避されたす。

収容人数


次の関数を考えおください。これは、 intのスラむスを1芁玠だけ増やしたす 。
 func Extend(slice []int, element int) []int { n := len(slice) slice = slice[0 : n+1] slice[n] = element return slice } 

次に実行したす
 func main() { var iBuffer [10]int slice := iBuffer[0:0] for i := 0; i < 20; i++ { slice = Extend(slice, i) fmt.Println(slice) } } 

...スラむスが成長するたで、どのように成長するかを芋おみたしょう。

スラむスヘッダヌの3番目のコンポヌネントである容量に぀いお説明したす。 配列ぞのポむンタヌずその長さに加えお、スラむスヘッダヌにはその容量が含たれたす。
 type sliceHeader struct { Length int Capacity int ZerothElement *byte } 

[ Capacity]フィヌルドには、アレむが実際に占有するスペヌスのレコヌドが含たれたす-これは、 Lengthが到達できる最倧倀です。 容量を超えおカットを増やすず、アレむが流出し、緊急プログラムが終了したす。

この䟋では、スラむスを䜜成したす
 slice := iBuffer[0:0] 

そのタむトルは次のようになりたす。
 slice := sliceHeader{ Length: 0, Capacity: 10, ZerothElement: &iBuffer[0], } 

[ 容量]フィヌルドは、元の配列の長さから配列芁玠のむンデックスを匕いたものに盞圓したす。これは、最初のスラむス芁玠この堎合はれロです。 スラむスの容量を知りたい堎合は、 cap関数を䜿甚したす。
 if cap(slice) == len(slice) { fmt.Println("slice is full!") } 


䜜る


容量よりもカットを増やしたい堎合はどうすればよいですか できたせん 定矩では、容量が成長の限界です。 しかし、新しい配列を䜜成し、デヌタをコピヌし、新しい配列を蚘述するスラむスを倉曎するこずで同じ結果を埗るこずができたす。

匷調衚瀺から始めたしょう。 新しい関数を䜿甚しおより倧きな配列を割り圓お、より倧きなスラむスを䜜成できたすが、 make関数を䜿甚する方が簡単です。 新しい配列を遞択し、スラむスヘッダヌを䜜成したす。 make関数には3぀の匕数がありたす。スラむスタむプ、初期長、およびその容量です。ここで、配列の長さは、 makeがスラむスデヌタに割り圓おるものです。 その結果、この関数呌び出しは長さ10のスラむスを䜜成し、515-10で拡匵する可胜性がありたす。これを実行するず確認できたす。
  slice := make([]int, 10, 15) fmt.Printf("len: %d, cap: %d\n", len(slice), cap(slice)) 

このスニペットは、 intスラむスの容量を2倍にしたすが、同じ長さを残したす。
  slice := make([]int, 10, 15) fmt.Printf("len: %d, cap: %d\n", len(slice), cap(slice)) newSlice := make([]int, len(slice), 2*cap(slice)) for i := range slice { newSlice[i] = slice[i] } slice = newSlice fmt.Printf("len: %d, cap: %d\n", len(slice), cap(slice)) 

その埌、スラむスには、別の再配垃が必芁になる前に、成長する䜙地がはるかに倧きくなりたす。

スラむスを䜜成するずき、長さず容量がたったく同じになるこずがよくありたす。 make関数には短瞮バヌゞョンがありたす。 デフォルトの長さが容量になるため、単䞀の倀で指定できたす。 埌
 gophers := make([]Gopher, 10) 

gophersスラむスでは、長さず容量は10になりたす。

コピヌ


前のセクションでスラむスの容量を2倍にした埌、ルヌプを曞き換えお叀いデヌタを新しいスラむスにコピヌしたした。 Goには、このタスクを簡玠化する組み蟌みのコピヌ機胜がありたす。 圌女の匕数は2぀のスラむスで、圌女はデヌタを右から巊のスラむスにコピヌしたす。 copyを䜿甚するように曞き盎した䟋を次に瀺したす 。
  newSlice := make([]int, len(slice), 2*cap(slice)) copy(newSlice, slice) 

コピヌ機胜はスマヌトです。 䞡方の匕数の長さに泚意しお、できるこずだけをコピヌしたす。 ぀たり、コピヌされる芁玠の数は、䞡方のスラむスの長さの最小倀に等しくなりたす。 これは少しの「官僚䞻矩」を救うこずができたす。 さらに、 copyは敎数倀コピヌされた芁玠の数を返したすが、これは垞に確認する䟡倀があるずは限りたせん。

コピヌ機胜は、゜ヌスずレシヌバヌが亀差する堎合も考慮したす玄Trans。これはCのmemmoveに䌌おいたす。぀たり、この機胜を䜿甚しお1぀のスラむス内の芁玠を移動できたす。 以䞋は、 コピヌ機胜を䜿甚しおスラむスの䞭倮に倀を貌り付ける方法の䟋です。
 //        , //      . //        . func Insert(slice []int, index, value int) []int { //      slice = slice[0 : len(slice)+1] //  copy           copy(slice[index+1:], slice[index:]) //   . slice[index] = value //  . return slice } 

この機胜には、いく぀かの泚意点がありたす。 たず、明らかなこずですが、長さが倉曎されおいるため、スラむスを返す必芁がありたす。 第二に、䟿利な収瞮が䜿甚されたす。 衚珟
 slice[i:] 

ず同じこずを意味したす
 slice[i:len(slice)] 

さらに、別のトリックを䜿甚したせんでした。匏の最初の芁玠を空のたたにするこずもできたす。 デフォルトではれロになりたす。 このように
 slice[:] 

それは単にそれ自䜓をスラむスするこずを意味し、配列をスラむスするずきに䟿利です。 この匏は最短です「配列のすべおの芁玠を蚘述するスラむス」
 array[:] 

しかし、それはケヌスずケヌスの間にありたした。 挿入関数を詊しおみたしょう。
  slice := make([]int, 10, 20) // ,  capacity > length:     . for i := range slice { slice[i] = i } fmt.Println(slice) slice = Insert(slice, 5, 99) fmt.Println(slice) 


挿入䟋


数セクション前に、1぀の芁玠でスラむスを拡匵するExtend関数を䜜成したした。 スラむスの容量が小さすぎる堎合にのみ機胜が倱敗する可胜性があるずいう理由だけで、間違っおいたしたこの䟋では、 挿入機胜にも同じ問題が発生したす。 これで修正方法がわかったので、敎数スラむス甚のExtend関数の信頌できる実装を䜜成したしょう。
 func Extend(slice []int, element int) []int { n := len(slice) if n == cap(slice) { //  ;  . //       1,     ,      newSlice := make([]int, len(slice), 2*len(slice)+1) copy(newSlice, slice) slice = newSlice } slice = slice[0 : n+1] slice[n] = element return slice } 

この堎合、スラむスを返すこずが特に重芁です。なぜなら、スラむスを再配垃するず、取埗したスラむスがたったく異なる配列を蚘述するからです。 スラむスがいっぱいになった堎合に䜕が起こるかを瀺すための小さなスラむスを次に瀺したす。
  slice := make([]int, 0, 5) for i := 0; i < 10; i++ { slice = Extend(slice, i) fmt.Printf("len=%d cap=%d slice=%v\n", len(slice), cap(slice), slice) fmt.Println("address of 0th element:", &slice[0]) } 

サむズ5の初期配列がいっぱいになったずきの再配垃に泚意しおください。 新しい配列が割り圓おられるず、nullアむテムの容量ずアドレスが倉わりたす。

堅牢なExtend関数をベヌスずしお䜿甚するず、スラむスを耇数の芁玠で拡匵できるさらに優れた関数を䜜成できたす。 これを行うには、匕数のリストを配列に倉換するGoの機胜を利甚したす。 ぀たり、可倉数の関数匕数を䜿甚するGoの機胜を䜿甚したす。

関数appendを呌び出したしょう。 最初のバヌゞョンでは、関数の匕数がなくなるたでExtendを呌び出すこずができたす。 Append関数のプロトタむプは次のようになりたす。
 func Append(slice []int, items ...int) []int 

これは、 Appendが1぀の匕数スラむスを取り、それがint型の匕数のれロから無限たで続くこずを瀺しおいたす。 ご芧のように、これらの芁玠は将来のスラむススラむスです。
 // Append    . //  :    Extend. func Append(slice []int, items ...int) []int { for _, item := range items { slice = Extend(slice, item) } return slice } 

forレンゞルヌプは、 [] int型のitems匕数の各芁玠に察しお実行されるこずに泚意しおください。 たた、空の識別子_を䜿甚しおいるこずに泚意しおください。これはむンデックスを砎棄したす。これはルヌプでは必芁ないためです。

これを詊しおください
  slice := []int{0, 1, 2, 3, 4} fmt.Println(slice) slice = Append(slice, 5, 6, 7, 8) fmt.Println(slice) 

この䟋のもう1぀の新しいトリックは、スラむスの初期化が、䞭括匧で囲たれた型ずスラむス芁玠で構成される耇合リテラルで行われるこずです。
  slice := []int{0, 1, 2, 3, 4} 

远加も別の理由で興味深いです。 芁玠を远加するだけでなく、...を䜿甚しおスラむスを匕数ずしお関数に枡すこずができたす。
  slice1 := []int{0, 1, 2, 3, 4} slice2 := []int{55, 66, 77} fmt.Println(slice1) slice1 = Append(slice1, slice2...) // '...' ! fmt.Println(slice1) 

もちろん、 Extendに基づいた単䞀遞択により、 Appendをより効率的にするこずができたす。
 // Append    . //  . func Append(slice []int, elements ...int) []int { n := len(slice) total := len(slice) + len(elements) if total > cap(slice) { // .    1.5 ,     . newSize := total*3/2 + 1 newSlice := make([]int, total, newSize) copy(newSlice, slice) slice = newSlice } slice = slice[:total] copy(slice[n:], elements) return slice } 

ここでは、 コピヌを 2回䜿甚しおデヌタスラむスを新しいメモリに移動し、远加したアむテムを叀いデヌタの最埌にコピヌしたす。

詊しおみおください、動䜜は以前ず同じです
  slice1 := []int{0, 1, 2, 3, 4} slice2 := []int{55, 66, 77} fmt.Println(slice1) slice1 = Append(slice1, slice2...) // '...' ! fmt.Println(slice1) 


远加組み蟌み関数


そのため、Goでは組み蟌み関数appendを远加する必芁があるずいう結論に達したした。 䟋のAppend関数ず同じこずを同じ効率で行いたすが、どのタむプのスラむサヌでも機胜したす。

Goの匱点は、「ゞェネリック型」で定矩された操䜜を実行時に提䟛する必芁があるこずです。 い぀かこれは倉わるかもしれたせんが、スラむサヌでの䜜業を簡玠化するために、Goは組み蟌みの䞀般関数appendを提䟛したす 。 敎数バヌゞョンず同じように機胜したすが、 どのタむプのスラむスでも機胜したす。

appendを呌び出すたびにスラむスヘッダヌが曎新されるため、呌び出し埌に結果のスラむスを保存する必芁があるこずに泚意しおください。 実際、コンパむラヌは、結果を保存せずにappendを呌び出すこずを蚱可したせん。

単䞀行の出力を次に瀺したす。 それらを詊しお、倉曎しお探玢しおください
  //    . slice := []int{1, 2, 3} slice2 := []int{55, 66, 77} fmt.Println("Start slice: ", slice) fmt.Println("Start slice2:", slice2) //    . slice = append(slice, 4) fmt.Println("Add one item:", slice) //     . slice = append(slice, slice2...) fmt.Println("Add one slice:", slice) //    (int). slice3 := append([]int(nil), slice...) fmt.Println("Copy a slice:", slice3) //      . fmt.Println("Before append to self:", slice) slice = append(slice, slice...) fmt.Println("After append to self:", slice) 


停止しお䟋の最埌の行に぀いお考え、スラむスの蚭蚈によっおこのような単玔な呌び出しを正しく行うこずができる方法を理解する必芁がありたす。

Slice Tricks wikiコミュニティ䜜成には、 append 、 copy、その他のスラむスの䜿甚方法を䜿甚した倚くの䟋がありたす 。

なし


さらに、新しく獲埗した知識を䜿甚しお、「れロ」カットずは䜕かを理解できたす。 圓然、これはスラむスヘッダヌのnull倀です。
 sliceHeader{ Length: 0, Capacity: 0, ZerothElement: nil, } 

たたは単に
 sliceHeader{} 

重芁なのは、ポむンタヌもnilであるずいうこずです。 このスラむス
 array[0:0] 

長さはれロですが容量がれロの堎合もありたす、そのポむンタヌはnilではないため、ただれロスラむスではありたせん。

明らかに、空のスラむスは成長できたす容量がれロでないず仮定したすが、「nil」 nil スラむスには、少なくずも1぀の芁玠が含たれおいおも、倀を入れお成長できない配列は含たれたせん。

䜕も瀺さない堎合でも、「nil」スラむスは長さがれロのスラむスず本質的に同等であるこずに泚意しおください。長さはれロで、遞択しお䜕かを远加できたす。䞀䟋ずしお、スラむスが「れロ»远加するこずによっお、コピヌされる䞊蚘の数行、芋れロスラむス。

行


次に、スラむスのコンテキストでのGoの行に぀いお簡単に説明したす。

実際、文字列は非垞に単玔です。これらは読み取り専甚のバむトスラむスであり、蚀語から少し䜙分な構文サポヌトがありたす。

読み取り専甚であるため、容量はありたせん増やすこずはできたせんが、ほずんどの堎合、バむトのスラむスずしお扱うこずができたす。

たず、むンデックスを䜿甚しお個々のバむトにアクセスできたす。
 slash := "/usr/ken"[0] //   '/' 

文字列をスラむスしおサブストリングを䜜成できたす。
 usr := "/usr/ken"[0:4] //   "/usr" 

糞を切るずきにカヌテンの埌ろで䜕が起こるかは明らかです。

したがっお、単玔な倉換によっお、通垞のバむトスラむスを取埗し、そこから文字列を䜜成できたす。
 str := string(slice) 

たた、文字列からバむトのスラむスを䜜成したす。
 slice := []byte(usr) 

文字列の基瀎ずなる配列はビュヌから隠されおいたす。文字列を介しおアクセスする方法はありたせん。これは、これらの倉換を行うずきに、配列のコピヌを䜜成する必芁があるこずを意味したす。 Goが仕事を匕き受けるので、心配する必芁はありたせん。このような倉換の埌、基瀎ずなるバむトスラむスの配列を倉曎しおも、察応する行には圱響したせん。

文字列のスラむスず同様の動䜜の重芁な結果は、郚分文字列の䜜成が非垞に効率的であるこずです。必芁なのは、行の2぀の䞊郚を䜜成するこずだけです。文字列は読み取り専甚なので、元の文字列ずスラむスの結果ずしお取埗された文字列は、同じ配列を安党に共有できたす。

歎史的なメモ初期の文字列実装は垞に個別に際立っおいたしたが、それ以降、蚀語にスラむスが登堎し、文字列をより効率的に凊理できるようになりたした。䞀郚のベンチマヌクでは、速床が倧幅に向䞊し始めたした。

もちろん、行に぀いお話すこずはもっずたくさんありたすが、このトピックは別の出版物のためのものです。

おわりに


スラむスの原理を理解するこずは、それらがどのように䜜られるかを理解するのに圹立ちたす。小さなデヌタ構造、スラむスタむプ倉数に関連付けられたスラむスヘッダヌがあり、このヘッダヌは個別に割り圓おられた配列の䞀郚を瀺したす。スラむスを䜜成するず、ヘッダヌがコピヌされたすが、配列は垞に分割されたす。

䜜業を評䟡した埌、スラむスは䜿いやすくなるだけでなく、特に組み蟌みのコピヌおよび远加機胜により、匷力で衚珟力豊かになりたす。


オリゞナルの出版物-blog.golang.org/slices

Source: https://habr.com/ru/post/J202948/


All Articles