آرایه و slice دو نوع تایپ با یک وجه اشتراک در زبان گو می باشند ولی این دو نوع تایپ یکسری تفاوت هایی نیز با هم دارند که در ادامه بهشون مپردازیم.
1.8.1 تعریف آرایه #
آرایه یکی از عمومی ترین تایپ ها در زبان های برنامه نویسی آرایه هاهستند که برای نگه داری گروهی مقادیر از یک نوع تایپ استفاده می شود. برای دسترسی به هرکدام از مقادیر درون آرایه باید از اندیس استفاده کرد. معمولا برای تعریف آرایه شما تعداد مشخص و ثابتی را برای تعداد مقادیر مشخص میکنید. یعنی این آرایه قرار است چندتا مقدار نگه داری کند.
در مثال زیر یک نمونه کد در خصوص چگونگی تعریف آرایه قرار داده ایم :
1package main
2
3import "fmt"
4
5func main() {
6 arrayInts := [5]int{1, 25, 12354, 654, 32}
7 fmt.Println(arrayInts)
8}
- یک متغیر کوتاه از نوع آرایه با نام arrayInts تعریف کردیم.
- ظرفیت آرایه را با عدد ۵ تعیین کردیم (یعنی این آرایه فقط ۵ تا مقدار بیشتر نگه داری نمی کند)
- سپس تایپ آرایه را از نوع int مشخص کردیم.
- در نهایت در همانجا آرایه را مقدار دهی کردیم. در زبان گو مقدار دهی با باز کردن
{}
به انگلیسیcurly bracket
انجام میشود.
1.8.2 مفهوم اندازه و ظرفیت (size, capacity) #
در آرایه ما ۲ تا مفهوم داریم اندازه و ظرفیت که از عنوان این مفهوم مشخص است آرایه دارای یک اندازه و ظرفیت مشخصی می باشد و اگر شما بیشتر از ظرفیت و اندازه تعیین شده مقدار دهی کنید با خطا مواجه خواهید شد.
در آرایه ظرفیت به نسبت اندازه تعیین می شود.
1package main
2
3import "fmt"
4
5func main() {
6 arrayString := [3]string{"a", "b", "c", "d"}
7 fmt.Println(arrayString)
8}
در کد فوق ما یک آرایه با اندازه ۳ تعریف کردیم و ۴ تا مقدار داخلش قرار دادیم و پس از اجرا, با خطای تعداد مقادیر بیشتر از اندازه و ظرفیت می باشد
مواجه شدیم.
1.8.2.1 تابع len و cap #
برای آرایه و slice ما ۲ تا تابع داریم که می توانیم اندازه و ظرفیت یک آرایه یا slice را بگیریم.
- تابع len یکی از توابع بسیار کاربردی و پراستفاده هنگام کار با آرایه یا slice می باشد که می توانید اندازه آرایه یا slice را بگیرید.
- تابع cap ظرفیت آرایه و slice را نمایش می دهد.
1package main
2
3import "fmt"
4
5func main() {
6 arrayString := [3]string{"a", "b", "c"}
7 fmt.Printf("array %v, len %d, cap %d", arrayString, len(arrayString), cap(arrayString))
8}
1.8.3 تعریف آرایه و مقدارهی #
در مثال زیر ما یک آرایه با مقدار 5 تعریف کردیم و قصد داریم در ادامه کد, آرایه رو مقداردهی کنیم.
1package main
2
3import "fmt"
4
5func main() {
6 nums := [5]int{}
7 fmt.Printf("array nums values %v, len %d, cap %d", nums, len(nums), cap(nums))
8
9 nums[0] = 1
10 nums[1] = 2
11 nums[2] = 10
12 nums[4] = 999
13
14 fmt.Println("")
15 fmt.Printf("array nums values %v, len %d, cap %d", nums, len(nums), cap(nums))
16}
1$ go run main.go
2array nums values [0 0 0 0 0], len 5, cap 5
3array nums values [1 2 10 0 999], len 5, cap 5
- در کد فوق در ابتدا ما یک آرایه بدون مقدار تعریف کردیم.
- سپس با استفاده از اندیس مقدار را در خانه مشخص قرار دادیم.
1.8.3.1 تعریف آرایه با اندازه تعیین شده توسط کامپایلر (شما اندازه رو بهش نمیدین.)
#
شما در زبان گو می توانید با استفاده از ...
بهش میگن Ellipsis
یک آرایه با اندازه مشخص شده توسط کامپایلر تعریف کنید.
1package main
2
3import "fmt"
4
5func main() {
6 nums := [...]int{1, 25, 45, 8797, 78, 879, 541, 11}
7 fmt.Printf("array nums values %v, len %d, cap %d", nums, len(nums), cap(nums))
8}
توجه کنید زمانیکه...
(Ellipsis)
برای تعریف آرایه استفاده می کنید فقط در همان لحظه تعریف می توانید آرایه رو مقدار دهی کنید.
1.8.3.2 تعریف آرایه دوبعدی یا چندبعدی #
در زبان گو همانند سایر زبان ها می توانید آرایه دوبعدی یا چند بعدی تعریف کنید. این نوع آرایه ها برای پیاده سازی ماتریس یا یکسری سناریوهای توسعه کاربردی می باشند.
1package main
2
3import "fmt"
4
5func main() {
6 nums := [2][2][2]int{{{1, 2}, {2, 3}}, {{4, 5}, {6, 7}}}
7 fmt.Printf("array nums values %v, len %d, cap %d", nums, len(nums), cap(nums))
8}
1.8.3.3 مقایسه آرایه ها #
در کد زیر ما یک نمونه از مقایسه آرایه ها را قرار داده ایم که این مقایسه براساس تایپ, اندازه و مقادیر در نظر گرفته شده است.
1package main
2
3import "fmt"
4
5func main() {
6 nums := [2]int{1, 2}
7 nums2 := [2]int{1, 3}
8 nums3 := [2]int{1, 2}
9 nums4 := [3]int{1, 2, 3}
10 chars := [2]string{"a", "b"}
11
12 fmt.Println(nums == nums2) // false
13 fmt.Println(nums == nums3) // true
14 fmt.Println(nums == nums4) // error: invalid operation: nums == nums4 (mismatched types [2]int and [3]int)
15 fmt.Println(nums == chars) // error: invalid operation: nums == chars (mismatched types [2]int and [2]string)
16}
1.8.4 برش (slice) #
همانطور که می دانید آرایه یکی از مهم ترین عناوین در زبان های برنامه نویسی می باشد. اما در زبان گو slice نسبت به آرایه بسیار پراستفاده و کاربردی تر است. اگر بخواهیم خیلی ساده slice را توصیف کنیم در واقع “یک slice به عنوان یک بخش بهم پیوسته از یک آرایه تعریف می شود که شما می توانید المنت هایش را در حال اجرا افزایش یا کاهش دهید بدون آنکه ظرفیت و اندازه آن را مشخص کنید.”
اما این سوال پیش می آید علت اینکه slice به نسبت آرایه کاربرد بیشتری دارد چیست؟ آرایه دارای برخی از محدودیت ها علی الخصوص, اندازه ثابت می باشد اما در slice شما این محدودیت ها را نخواهید داشت و خیلی ساده می توانید المنت ها را افزایش, حذف و حتی کپی کنید.
در زبان گو slice ها یک پارچگی آرایه را حفظ می کنند و کار با آرایه خیلی ساده و آسان تر خواهد شد.
1.8.4.1 تعریف یک slice با اندازه مشخص #
شما می توانید با استفاده از تابع make
یک slice با اندازه مشخص تعریف کنید.
1slice := make([]int, 5)
2
3fmt.Println(len(slice)) // Print 5
4
5fmt.Println(cap(slice)) // Print 5
1.8.4.2 تعریف یک slice با اندازه و ظرفیت مشخص #
شما می توانید با استفاده از تابع make
یک slice با ظرفیت و اندازه مشخصی تعریف کنید.
1slice := make([]int, 3, 5)
2
3fmt.Println(len(slice)) // Print 3
4
5fmt.Println(cap(slice)) // Print 5
توجه کنید مقدار ظرفیت نباید کمتر از مقدار اندازه باشد.
1.8.4.3 تعریف یک slice با متغیر کوتاه short variable declaration
#
شما خیلی ساده می توانید یک slice را توسط متغیر کوتاه ایجاد کنید.
1slice := []string{"Red", "Blue", "Green", "Yellow", "Pink"}
2
3fmt.Println(len(slice)) //Print 5
4
5fmt.Println(cap(slice)) //Print 5
6
7intSlice:= []int{10, 20, 30}
8
9fmt.Println(len(intSlice)) //Print 3
10
11fmt.Println(cap(intSlice)) //Print 3
1.8.4.4 تعریف یک slice با موقعیت های شاخص #
شما می توانید یک slice را با موقعیت های شاخص ایجاد کنید که n تا المنت با مقدار پیش فرض ایجاد می کند و در آخر x را به آخر slice اضافه می کند. (در مثال زیر ۹۹ تا المنت با مقدار 0 و در اخر یک المنت با مقدار 88)
درست میکند.
1package main
2
3import "fmt"
4
5func main() {
6 test := []int{99: 88}
7 fmt.Println(len(test), cap(test))
8}
1.8.4.5 تعریف یک slice خالی #
شما می توانید خیلی ساده یک slice خالی ایجاد کنید.
1sliceOne := make([]int, 0)
2
3sliceTwo := []int{}
4
5fmt.Println(sliceOne == nil) // print false
6
7fmt.Println(len(sliceOne)) // print 0
8
9fmt.Println(cap(sliceOne)) // print 0
10
11fmt.Println(sliceTwo == nil) // print false
12
13fmt.Println(len(sliceTwo)) // print 0
14
15fmt.Println(cap(sliceTwo)) // print 0
1.8.5 مقدار دهی مجدد یکی از المنت های slice یا آرایه #
شما خیلی راحت می توانید مقدار یکی از المنت های slice یا آرایه را مقدار دهی کنید.
1slice := []int{10, 20, 30, 40}
2
3fmt.Println(slice) //print [10 20 30 40]
4
5slice[1] = 25
6
7fmt.Println(slice) // print [10 25 30 40]
1.8.6 ایجاد یک slice جدید براساس یک slice از پیش تعریف شده #
شما می توانید یک slice جدید را براساس یک slice از پیش تعریف شده ایجاد کنید.
1x := []int{10, 20, 30, 40, 50}
2
3fmt.Println(x) // Print [10 20 30 40 50]
4
5fmt.Println(len(x)) // Print 5
6
7fmt.Println(cap(x)) // Print 5
8
9y := x[1:3]
10
11fmt.Println(y) //Print [20 30]
12
13fmt.Println(len(y)) //Print 2
14
15fmt.Println(cap(y)) //Print 4
- ما یک متغیر با نام
x
با ۵ تا المنت مقدار دهی شده تعریف کردیم. - سپس یک متغیر کوتاه با نام y تعریف کردیم که متغیر x را داخلش قرار دادیم.
- سپس به متغیر x گفتیم از اندیس ۱ تا ۳ را به y اختصاص بدهد.
توجه کنید اتفاقی که مثال بالا رخ داد این بود که ما, اندازه و ظرفیت جدیدی برای متغیر y تعیین کردیم.
Len: 3 - 1 = 2 Cap: 5 - 1 = 4
1.8.7 خطای index out of range در slice #
یک slice فقط با توجه به اندازه و اندیس هاش امکان دسترسی و مقدار دهی مجدد المنت هایش را میدهد, اما اگر شما بخاهید خارج از اندازه تعیین شده جهت مقداری دهی و یا دسترسی به slice اقدام کنید با خطای index out of range مواجه خواهید شد.
1package main
2
3import "fmt"
4
5func main() {
6 slice := []int{10, 20, 30, 40, 50}
7 newSlice := slice[1:3]
8 newSlice[3] = 45
9 fmt.Println(newSlice)
10}
1$ go run main.go
2panic: runtime error: index out of range [3] with length 2
3
4goroutine 1 [running]:
5main.main()
6 /tmp/sandbox548843089/prog.go:8 +0x5b
1.8.8 افرودن (append) المنت های یک slice #
شما خیلی ساده می توانید با استفاده از تابع append
به المنت های یک slice بیفزایید .
1slice := []int{10, 20, 30, 40, 50}
2
3newSlice := slice[1:3]
4
5fmt.Println(len(newSlice)) // Print 2
6
7fmt.Println(cap(newSlice)) // Print 4
8
9newSlice = append(newSlice, 60)
10
11fmt.Println(len(newSlice)) // Print 3
12
13fmt.Println(cap(newSlice)) // Print 4
در کد زیر اتفاقی که صورت گرفته است این است که اگر شما
...
Ellipsis
را بعد از کلمه slice بزارید یعنی دارید میگید تمامی المنت های داخل slice به newSlice اضافه شود.
1.8.9 نحوه حذف یک المنت در slice #
برای حذف یک المنت در slice باید بصورت تکنیکی اینکار را انجام دهید چون زبان گو یک روش built-in برای اینکار ندارد.
- در این روش شما باید در ابتدا آخرین المنت را به المنت مورد نظر با استفاده از اندیس کپی کنید.
- سپس آخرین المنت را از slice حذف کنید.
1package main
2
3import "fmt"
4
5func main() {
6 slice := []int{10, 20, 30, 40, 50}
7 slice[1] = slice[len(slice)-1]
8 slice = slice[:len(slice)-1]
9 fmt.Println(slice)
10}
- یک روش دیگر برای حذف یک المنت از slice استفاده از تابع
append
است. - به مثال زیر توجه کنید.
1package main
2
3import "fmt"
4
5func main() {
6 slice := []int{1, 2, 3, 4, 5}
7 index := 2 // ایندکس المنتی که میخاییم حذفش کنیم
8 slice = append(slice[:index], slice[index+1:]...)
9 fmt.Println(slice) // خروجی: [1 2 4 5]
10}
1.8.10 تابع copy در slice #
شما با استفاده از تابع copy
می توانید یک slice را به slice دیگری کپی کنید.
1package main
2
3import "fmt"
4
5func main() {
6 src := []int{1, 2, 3, 4, 5}
7 dst := make([]int, 5)
8 numberOfElementsCopied := copy(dst, src)
9 fmt.Println(numberOfElementsCopied, dst)
10}
1.8.11 نحوه مرتب کردن (sort) یک slice #
برای مرتب کردن یک slice می توانید از توابع کتابخانه sort در زبان گو استفاده کنید.
sort.Ints
sort.Float64s
sort.Strings
1package main
2
3import (
4 "fmt"
5 "sort"
6)
7
8func main() {
9 s := []int{4, 2, 3, 1}
10 sort.Ints(s)
11 fmt.Println(s)
12}
1.8.12 فرق بین آرایه و slice #
- فرق نوع تعریف آرایه و slice
- برای تعریف آرایه شما باید داخل براکت [] یک مقداری را قرار دهید.
- برای تعریف slice هیچ مقداری را داخل براکت [] نباید قرار دهید.
- فرق بین خالی بودن
آرایه و slice
- مقدار خالی یک slice هست nil
- مقدار خالی یک آرایه, همان آرایه با المنت های مقدار پیش فرض می باشد.