ในครั้งนี้ทำการศึกษาในเรื่อง function new, make
ทำความรู้จักกับ Data structure พื้นฐาน นั่นคือ Array, Slice และ Map
ดูว่าแต่ละตัวทำงานอย่างไร มีอะไรที่เหมือนและแตกต่าง
พร้อม code ตัวอย่าง
เริ่มต้นด้วยการจองพื้นที่ในหน่อยความจำ
ใน go มี 2 function คือ new กับ make
ทั้งสอง function ใช้งานแตกต่างกัน แต่มักจะสับสน
ดังนั้นมาทำความเข้าใจในแต่ละตัวดีกว่า
New
การใช้งานคือ new(T)
ทำงานแตกต่างจากการ new ในภาษาอื่นๆ
โดยจะทำการจองหน่อยความจำเท่ากับค่า default ของแต่ละชนิดข้อมูล เช่น
bool คือ false
integer คือ 0
float คือ 0.0
string คือ “”
pointers, functions, interfaces, slices, channels, maps คือ nil
และจะส่งค่าตำแหน่งของในหน่วยความจำกลับมาให้
ตัวอย่าง code
q := new([]int) fmt.Println(*q) fmt.Printf("Value = nill ? =>%t\n",*q==nil)
คำอธิบาย
ทำการสร้าง array ของเลขจำนวนเต็มขึ้นมา
แล้วแสดงผลค่าพบว่า มีค่า
[] คือ array ว่าง
และมีค่าเป็น nill
Make
การใช้งานคือ make(T, args)
ซึ่งเป้าหมายแตกต่างจาก new
เนื่องจาก make ใช้สำหรับการสร้าง slice, map และ channel เท่านั้น
และทำการ return ค่ากลับมา พร้อมการกำหนดค่าเริ่มต้น
และสิ่งที่ return กลับมาไม่ใช่ pointer นะ !!
ตัวอย่าง code
p := make([]int, 10, 100) fmt.Println(p) fmt.Println(p==nil) fmt.Println(len(p))
คำอธิบาย
ทำการสร้าง array ขนาด 10 และสามารถขยายไปจนถึง 100 ได้
เมื่อแสดงค่าต่างๆ จะได้
[0 0 0 0 0 0 0 0 0 0] = คือข้อมูลที่ถูกสร้างขึ้นมา ในแต่ละ index ของ array มีการกำหนดค่าให้แล้ว
false = ค่าไม่เป็น nil
10 = ความยาวของ array
มาดูพวก Data Structure กันบ้าง
Array
ใช้สำหรับการจองหน่วยความจำ ตามที่ได้วางแผนหรือต้องการใช้
ทำให้ไม่มีปัญหาเรื่องการจัดการหน่วยความจำ
Array ใน Go นั้นแตกต่างจาก C ดังนี้
1. Array คือ value ไม่ใช่ reference นะ
ดังนั้นเมื่อทำการกำหนดค่าให้กับตัวแปรใดๆ มันคือการ copy ทุกๆ อย่างไปนั่นเอง
2. ถ้าส่ง Array ไปยัง function นั่นคือการ pass by value ไม่ใช่ pass by reference นะ
3. ขนาดของ array จะเป็นส่วนหนึ่งของ type ดังนั้น [10]int กับ [20]int จึงไม่ใช่ type เดียวกันนะ
ดังนั้น Array นั้นมีประโยชน์ แต่ก็แลกมาด้วยการใช้ทรัพยากรที่สูงขึ้น
แต่สามารถแก้ไขด้วยการส่ง pointer ของ Array ไป เช่น
func Sum(a *[3]float64) (sum float64) { for _, v := range *a { sum += v } return } func main() { array := [...]float64{7.0, 8.5, 9.1} x := Sum(&array) fmt.Println(x) }
แต่ใน Go แนะนำให้ไปใช้ Slice จะดีกว่านะ
เพราะว่ารูปแบบที่ใช้ดัง code ข้างต้นมันฝืนกับตัวภาษา
Slice
จะทำการหุ้ม Array ไว้นั่นเอง
มีประสิทธิภาพที่ดี สำหรับข้อมูลที่เรียงกัน
โดยใน Go จะใช้ slice เป็นตัวหลัก
Slice จะทำการเก็บ reference ของ Array
ดังนั้นถ้ามีการกำหนดค่าไปยังตัวแปรใดๆ มันก็คือการกำหนด reference ให้นั่นเอง
ซึ่งทำให้ใช้งานบน Array ตัวเดียวกัน
ในการประกาศตัวแปรใช้งาน slice ทำได้ 2 แบบดังตัวอย่าง
letters := []string{"a", "b", "c", "d”} var s []string = make([]string, 5, 5)
และมี build-in function ให้ 2 ตัวคือ len กับ cap สำหรับดูขนาดและความจุของ slice
ส่วนการเข้าถึงข้อมูลใน slice สามารถทำได้ดังนี้
letters := []string{"a", "b", "c", "d"} fmt.Println(letters[1]) fmt.Println(letters[:]) fmt.Println(letters[:4]) fmt.Println(letters[1:2]) fmt.Println(letters[1:4]) fmt.Println(letters[1:])
ผลการทำงานเป็นดังนี้
b
[a b c d]
[a b c d]
[b]
[b c d]
[b c d]
และยังสามารถใช้ slice แบบ 2 มิติได้อีกด้วย
สรุปแล้วใช้ Slice แทน Array ซะนะ
Go ยังมี build-in function สำหรับ Slice อีก คือ Append
เพื่อไว้เพิ่มข้อมูลที่ท้ายของ Slice
letters := []string{"a", "b", "c", "d"} letters = append(letters, "e", "f”)
และถ้าต้องการเชื่อมต่อ slice เข้าด้วยกัน สามารถทำได้ดังนี้
x := []int{1,2,3} y := []int{4,5,6} x = append(x, y...)
Map
มันก็คือ Data structure แบบ Key-value นั่นเอง
โดยที่ key อยากให้มีชนิดข้อมูลอะไรก็ได้ จัดไป
แต่ก็มีข้อยกเว้นนั่นคือ Slice จะนำมาเป็น key ไม่ได้
ใน Map นั่นมันส่งค่ากันแบบ reference เหมือน Slice นะ
ดังนั้นไม่ต้องกังวลแบบ Array
การประกาศใช้งานก็ง่ายๆ ดังนี้
teams := map[string]int { "MAN U": 20, "MANCI": 30, }
ส่วนการเข้าถึงข้อมูล
score := teams["MAN U"]
ทำการตรวจสอบว่ามีข้อมูลตาม key ที่ต้องการหรือไม่
if teams[“XXX”] { }
หรือสามารถใช้แบบนี้ได้ ซึ่งใช้เมื่อต้องการตรวจสอบค่าว่าเจอหรือไม่ เพื่อการแสดงรายงานต่างๆ ที่สวยงาม
var score int var ok bool score, ok = teams["MANU"] fmt.Println(score) fmt.Println(ok)
หรือต้องการเพียงดูว่ามีข้อมูลหรือไม่
สามารถใช้ blank identifier ได้ ดังนี้
_, ok := teams["MANU"]
ถ้าต้องการลบข้อมูลสามารถใช้ Delete function
เป็น build-in function ของ Map อยู่แล้ว
delete(teams, “MAN U")
Reference Websites
http://blog.golang.org/go-slices-usage-and-internals
http://blog.golang.org/go-maps-in-action
http://golang.org/doc/effective_go.html#data
http://golang.org/pkg/fmt/
http://golang.org/ref/spec#The_zero_value
http://dave.cheney.net/2013/01/19/what-is-the-zero-value-and-why-is-it-useful