Mastering Go Clices: شیرجه عمیق از صفر به قهرمان

برش های Go سنگ بنای زبان است و یک روش انعطاف پذیر برای کار با توالی داده ها ارائه می دهد. آنها آرایه نیستند ، اما در بالای آنها ساخته شده اند و درک می کنند که چگونه آنها در زیر کاپوت کار می کنند می توانند برنامه نویسی GO شما را بالا ببرند. این پست برش هایی را از اصول اولیه به موارد پیشرفته استفاده می کند ، با نمونه های واضح و نکات عملی. بیایید شیرجه بزنیم.
برش ها چیست؟
یک برش در GO است ساختار سبک وزن این یک پنجره را به یک آرایه زیرین فراهم می کند. بر خلاف آرایه ها ، که دارای طول ثابت هستند ، برش ها پویا هستند ، به این معنی که می توانید آنها را رشد داده یا کوچک کنید (در محدوده). یک برش توسط سه مؤلفه تعریف شده است: الف اشاره کننده به آرایه ، الف طول (تعداد عناصر در دسترس) ، و الف ظرفیت (کل عناصر موجود در آرایه اساسی).
در اینجا یک مثال ساده برای نشان دادن یک برش در عمل وجود دارد:
package main
import "fmt"
func main() {
// Create a slice directly
numbers := []int{1, 2, 3, 4, 5}
fmt.Println("Slice:", numbers)
fmt.Println("Length:", len(numbers))
fmt.Println("Capacity:", cap(numbers))
}
// Output:
// Slice: [1 2 3 4 5]
// Length: 5
// Capacity: 5
برش ها با اعلام می شوند []type
، و می توانید آنها را با استفاده از تحت اللفظی (مانند بالا) یا موارد ایجاد کنید make
عملکرد. اگر می خواهید اطلاعات بیشتری داشته باشید ، وبلاگ Go دارای شیرجه عمیق بسیار خوبی در قسمت داخلی برش است.
ایجاد برش: روشهای زیادی
شما می توانید برش هایی را از چند طریق ایجاد کنید که هر کدام مورد استفاده خود را دارند. در اینجا یک شکست:
روش | نحو | چه زمانی استفاده کنید |
---|---|---|
لفظی | s := []int{1, 2, 3} |
تنظیم سریع با مقادیر شناخته شده |
make |
s := make([]int, len, cap) |
طول و ظرفیت قبل از اختصاص |
از آرایه | s := arr[start:end] |
با بخشی از یک آرایه موجود کار کنید |
نیل برش | var s []int |
یک برش خالی را آغاز کنید (بدون تخصیص) |
در اینجا یک مثال کامل نشان داده شده است که روشهای مختلف آفرینش را نشان می دهد:
package main
import "fmt"
func main() {
// Slice literal
literal := []int{10, 20, 30}
fmt.Println("Literal slice:", literal)
// Using make
made := make([]int, 2, 5)
made[0], made[1] = 1, 2
fmt.Println("Made slice:", made, "Len:", len(made), "Cap:", cap(made))
// From array
array := [5]int{100, 200, 300, 400, 500}
fromArray := array[1:4]
fmt.Println("From array:", fromArray)
// Nil slice
var nilSlice []int
fmt.Println("Nil slice:", nilSlice, "Is nil?", nilSlice == nil)
}
// Output:
// Literal slice: [10 20 30]
// Made slice: [1 2] Len: 2 Cap: 5
// From array: [200 300 400]
// Nil slice: [] Is nil? true
نکته اصلی: استفاده کنید make
وقتی می دانید که اندازه پیش رو برای جلوگیری از مجالس سازی است.
برش نحو: برش آرایه ها مانند یک حرفه ای
نحو برش s[start:end]
به شما امکان می دهد یک برش جدید از یک آرایه یا یک برش دیگر ایجاد کنید. در start
فهرست فراگیر است ، و end
منحصر به فرد است همچنین می توانید از فهرست سوم استفاده کنید ، s[start:end:max]
، برای کنترل ظرفیت.
در اینجا یک مثال آورده شده است:
package main
import "fmt"
func main() {
array := [6]int{0, 1, 2, 3, 4, 5}
// Basic slicing
s1 := array[1:4]
fmt.Println("s1:", s1, "Len:", len(s1), "Cap:", cap(s1))
// Slice with max capacity
s2 := array[1:4:5]
fmt.Println("s2:", s2, "Len:", len(s2), "Cap:", cap(s2))
// Full slice
s3 := array[:]
fmt.Println("s3:", s3, "Len:", len(s3), "Cap:", cap(s3))
}
// Output:
// s1: [1 2 3] Len: 3 Cap: 5
// s2: [1 2 3] Len: 3 Cap: 4
// s3: [0 1 2 3 4 5] Len: 6 Cap: 6
نکته اصلی: ظرفیت یک برش با طول آرایه زیرین از start
فهرست به پایان آرایه یا max
فهرست
افزودن به برش ها: در حال رشد با append
در append
عملکرد نحوه اضافه کردن عناصر به یک برش است. اگر آرایه زیرین ظرفیت کافی داشته باشد ، append
از آن استفاده می کند در غیر این صورت ، GO یک آرایه جدید و بزرگتر را اختصاص می دهد. این می تواند بر عملکرد تأثیر بگذارد ، بنابراین از قبل با make
اغلب برای برش های بزرگ بهتر است.
مثال:
package main
import "fmt"
func main() {
s := []int{1, 2}
fmt.Println("Before:", s, "Len:", len(s), "Cap:", cap(s))
// Append one element
s = append(s, 3)
fmt.Println("After one:", s, "Len:", len(s), "Cap:", cap(s))
// Append multiple elements
s = append(s, 4, 5, 6)
fmt.Println("After many:", s, "Len:", len(s), "Cap:", cap(s))
}
// Output:
// Before: [1 2] Len: 2 Cap: 2
// After one: [1 2 3] Len: 3 Cap: 4
// After many: [1 2 3 4 5 6] Len: 6 Cap: 8
توجه کنید که چگونه ظرفیت (2 → 4 → 8) در هنگام رشد برش دو برابر می شود. مشخصات GO این رفتار را توضیح می دهد.
نکته اصلی: همیشه نتیجه را اختصاص دهید append
بازگشت به برش ، زیرا ممکن است یک قطعه جدید را برگرداند.
کپی برش ها: جلوگیری از مشکلات مشترک داده ها
برش ها آرایه اساسی خود را به اشتراک می گذارند ، که می تواند منجر به رفتار غیر منتظره شود. در copy
عملکرد یک قطعه جدید با آرایه خاص خود ایجاد می کند و عناصر را از منبع کپی می کند.
در اینجا مثالی وجود دارد که تفاوت را نشان می دهد:
package main
import "fmt"
func main() {
src := []int{1, 2, 3, 4}
dst := make([]int, 2)
// Copy first two elements
n := copy(dst, src)
fmt.Println("Copied:", dst, "Elements copied:", n)
// Modify source
src[0] = 99
fmt.Println("Source after mod:", src)
fmt.Println("Dest after mod:", dst)
}
// Output:
// Copied: [1 2] Elements copied: 2
// Source after mod: [99 2 3 4]
// Dest after mod: [1 2]
نکته اصلی: استفاده کنید copy
هنگامی که برای جلوگیری از تغییر داده های اصلی به یک قطعه مستقل نیاز دارید.
slice gotchas: اشتباهات رایج برای جلوگیری از
برش ها قدرتمند هستند اما می توانند به شما سفر کنند. در اینجا مشکلات مشترک وجود دارد:
اشتباه | مشکل | ثابت کردن |
---|---|---|
اصلاح آرایه های مشترک | تغییرات در یک برش بر دیگران تأثیر می گذارد | استفاده کردن copy یا یک برش جدید ایجاد کنید |
وحشت نیل | دسترسی به عناصر در یک قطعه صفر | بررسی کردن nil یا اولیه کردن |
خارج از مرز | دسترسی به فراتر از طول | استفاده کردن len برای بررسی مرزها |
نمونه ای از مسئله آرایه مشترک:
package main
import "fmt"
func main() {
array := [4]int{1, 2, 3, 4}
s1 := array[:2]
s2 := array[1:3]
s1[1] = 99
fmt.Println("s1:", s1)
fmt.Println("s2:", s2) // s2 is affected!
}
// Output:
// s1: [1 99]
// s2: [99 3]
نکته اصلی: همیشه هنگام کار با چندین برش از آرایه زیرین آگاه باشید.
نکات عملکرد: کارآمد ساختن برش
برش ها سریع هستند ، اما سوء استفاده می تواند برنامه شما را کند کند. در اینجا نکاتی برای بهینه سازی وجود دارد:
-
پیش اختصاص با
make
: طول و ظرفیت را برای جلوگیری از بازگرداندن تنظیم کنید. -
به حداقل رساندن
append
فراخوانی: دسته ای برای کاهش کپی کردن آرایه. -
استفاده کردن
copy
عاقلانه: فقط آنچه را که برای جلوگیری از سربار غیر ضروری لازم دارید کپی کنید.
نمونه ای از پیشگیری در مقابل رشد پویا:
package main
import "fmt"
func main() {
// Pre-allocated
s1 := make([]int, 0, 100)
for i := 0; i < 100; i++ {
s1 = append(s1, i)
}
fmt.Println("Pre-allocated len:", len(s1), "cap:", cap(s1))
// Dynamic growth
s2 := []int{}
for i := 0; i < 100; i++ {
s2 = append(s2, i)
}
fmt.Println("Dynamic len:", len(s2), "cap:", cap(s2))
}
// Output:
// Pre-allocated len: 100 cap: 100
// Dynamic len: 100 cap: 128
نکته اصلی: قبل از تخصیص ، تخصیص حافظه را کاهش داده و عملکرد را بهبود می بخشد.
الگوهای برش عملی: در دنیای واقعی استفاده می کند
برش ها در سناریوهای دنیای واقعی می درخشند. در اینجا دو الگوی مشترک وجود دارد:
- تصفیه: یک برش جدید با عناصر مطابق با یک شرط ایجاد کنید.
- چاک دهی: یک برش را به برش های کوچکتر تقسیم کنید.
مثال فیلتر:
package main
import "fmt"
func main() {
numbers := []int{1, 2, 3, 4, 5, 6}
evens := []int{}
for _, n := range numbers {
if n%2 == 0 {
evens = append(evens, n)
}
}
fmt.Println("Evens:", evens)
}
// Output:
// Evens: [2 4 6]
برای جمع آوری یا الگوهای دیگر ، راهنمای GO موثر را بررسی کنید.
با برش ها به کجا بروید
برش ها یک بخش اساسی از GO هستند و تسلط بر آنها کدگذاری کارآمد و اصطلاحات را باز می کند. برای تعمیق درک خود ، این مراحل را امتحان کنید:
- آزمایش: برای آزمایش رفتار برش ، مانند تغییر اندازه یا به اشتراک گذاری آرایه ها ، برنامه های کوچک بنویسید.
-
منبع را بخوانید: اجرای برش Go Runtime (در
runtime/slice.go
) نشان می دهد که چگونهappend
و کار رشد -
کد خود را مشخص کنید: از Go استفاده کنید
pprof
ابزاری برای نشان دادن مسائل مربوط به عملکرد مربوط به برش. -
کتابخانه ها را کاوش کنید: نگاه کنید که بسته ها چگونه هستند
sort
یاcontainer
از برش ها استفاده کنید.
برش ها ممکن است ساده به نظر برسند ، اما انعطاف پذیری و عملکرد آنها باعث می شود که آنها در ابزار ابزار توسعه دهنده GO به ابزاری قدرتمند تبدیل شوند. تمرین خود را ادامه دهید ، و مانند یک حرفه ای خرد خواهید شد.