มือใหม่หัดทำความเข้าใจ ภาษา Golang


ทำไมถึงสนใจ และมาหัด Golang

ด้วยความที่เป็นกำลังหาภาษาทางเลือกใหม่ๆ เพื่ออัพเดทสกิลตัวเอง และเคยไปสงสัยว่า ทำไม Software ดังๆ อย่าง Docker หรือ Kubernetes ถึงหันมาให้ จนเคย ไปค้นหาเหตุผลว่าทำไม Docker ถึงเขียนด้วย Go จนเจอ Post นึงใน Reddit

Why is Docker written in Go? : docker

1.png

และมีคนตอบซึ่งทำงานอยู่ที่ Docker เลย ได้ตอบว่า

2.png

ทำให้เกิดสนใจอย่างศึกษาขึ้นมา


“Go is an open source programming language that makes it easy to build simple, reliable, and efficient software”

รู้จัก Golang


Go สร้างที่ Google โดย Robert Griesemer, Rob Pike, และ Ken Thompson

ตัว Go เป็น statically typed คือ เมื่อมีการประกาศตัวแปรจะมีการกำหนด Type ของตัวแปร และจะทำการตรวจสอบ Type ที่เรากำหนดว่าถูกต้องหรือไม่ตั้งแต่ก่อน Compile ทั้งนี้ ตัวGoเองเป็น compiled programming language นั้นคือ เมื่อ Compile ตัว Go จะสร้างไฟล์ผลลัพธ์ออกมาในรูปของ Execute File แล้วทำไปใช้งานได้เลย

go.jpg


เบี้องต้น Golang คร่าวๆ

การจัดโค้ด

Go เองมีคำสั่งที่ใช้ในการจัด code ให้ โดยจะใช้คำสั่ง

  • gofmt
package main
import "fmt"

func main() {
	fmt.Println("Hello")
}

เมื่อสั่ง gofmt -w main.go จะได้ประมาณนี้

package main

import "fmt"

func main() {
	fmt.Println("Hello")
}

Package

ถึงไฟล์ Go จะประกอบด้วย package เสมอ โดย จะเริ่มทำงานจากไฟล์ที่มี package main

package main

import "fmt"

func main() {
    fmt.Println("Hello")
}

การ Import Library หรือ Dependency

import "fmt"
import "net/http"
......
......
import (
  "fmt"
  "net/http"
)

การใช้ Function

func < ชื่อ Function>(<ตัวแปร> <type>) {
    ...
}
...
package main

import "fmt"

func Hello(name string) {
	fmt.Println(name)
}
func main() {
	Hello("hello")
}

กรณี ต้องการ คืนค่ากลับ

func hello() string {

}

ตัวแปรใน Golang

  • Manual Type Declaration

ระบุตัวแปรพร้อม Data type

var name string
name = "jaedsada"

โดยการประกาศ แบบนี้ ค่าของตัวแปรจะเป็น default ( zero value ) ของแต่ละ type

3.png

  • Type Inference

เป็นการ กำหนด ตัวแปรพร้อม ระบุค่า โดยใช้ :=

name := "jaedsada"

เป็นการ กำหนดว่า name เป็น string พร้อมทั้งระบุค่า


การใช้ For-loop

for i := 1; i <= 10; i++ {
  fmt.Println(i)
}
...
...
sum := 1
for ; sum < 100; {
  sum += sum
}
fmt.Println(sum)
...
...
sum := 1
for sum < 100 {
  sum += sum
}
fmt.Println(sum)

การใช้ If statement

var i = 3
if i % 2 == 0 {
  fmt.Println("even")
} else {
  fmt.Println("odd")
}
...
...
var i = 3
if i%2 == 0 {
  fmt.Println("even")
}
fmt.Println("odd")

การใช้ Switch Case

fmt.Println("When's Saturday?")

today := time.Now().Weekday()

switch time.Saturday {
case today + 0:
  fmt.Println("Today.")
case today + 1:
  fmt.Println("Tomorrow.")
case today + 2:
  fmt.Println("In two days.")
default:
  fmt.Println("Too far away.")
}

การใช้ Defer

เมื่อประกาศ Defer หน้าคำสั่งอะไรสักอย่าง จะทำงานเมื่อ การทำงานอื่นๆทำเสร็จ

func main() {
	defer fmt.Println("world")

	fmt.Println("hello")
}
...
hello
world
func main() {
	defer fmt.Println("1")
	defer fmt.Println("2")

	fmt.Println("3")
}
...
3
2
1
func main() {
	defer fmt.Println("2")
	defer fmt.Println("1")

	fmt.Println("3")
}
...
3
1
2

การใช้ Array และ Slice

  • ประกาศ Array แบบระบุขนาด
var name [3]string
name[0] = "AA"
name[1] = "BB"
name[2] = "CC"
...
name := [3]string{"AA","BB","CC"}
  • Slice
name := []string
name = append(name,"AA")
name = append(name,"BB")
name = append(name,"CC")
...
name := []string{"AA","BB","CC"}

การนำ Array มา for loop

name := []string{"AA","BB","CC"}
for index , data := range name {
    fmt.Println(index, name)
}

....
0 AA
1 BB
2 CC

การใช้ Struct

เป็นชุดโครงสร้างของข้อมูล

type User struct {
    name string
    age int
}
package main

import "fmt"

type User struct {
    name string
    age int
}

func main() {
  userA := User{name: "UserA" , age: 100}
	fmt.Println(userA.name)
}

การใช้ Pointer

package main

import "fmt"

type User struct {
	name string
	age  int
}

func Hello(u User) {
	u.age = u.age + 100
	fmt.Println("new age", u.age)
}

func main() {
	userA := User{name: "userA", age: 23}
	Hello(userA)
	fmt.Println("age", userA.age)
}
...
new age 123
age 23

จะเห็นได้ว่า ได้ทำการส่ง ค่า 100 ไป บวก กับ อายุเดิม ได้เป็น new age แต่ ค่าที่ได้จริง จะได้เป็น ค่าเดิม ด้วยความที่ Function ใน Go มีการรับ Parameter แบบ Pass by values คือ มีการ จอง memory ให้ parameter เพื่อ copy ค่าไปยัง address ใหม่ ทำให้ไม่ได้ค่าจาก Function ข้างบนมา

***วิธีแก้คือเราต้องส่ง Reference ของ userA ไปให้กับฟังก์ชัน โดยที่ฟังก์ชันเมื่อได้รับ reference มาแล้วต้องทำการ ถอดเอาค่าที่แท้จริงออกมา (deference) ***

package main

import "fmt"

type User struct {
	name string
	age  int
}

func Hello(u *User) { // * เป็นการถอดค่าที่แท้จริงออกมา
	u.age = u.age + 100
	fmt.Println("new age", u.age)
}

func main() {
	userA := User{name: "userA", age: 23}
	Hello(&userA) // & อ้างถึง Reference
	fmt.Println("age", userA.age)
}
...
new age 123
age 123

การติตตั้ง Golang

  • On MacOS
$ brew install golang
  • Setup Path
$ vi ~/.bash_profile

...
export GOROOT=/usr/local/Cellar/go/1.13.7/libexec
export GOPATH={path_destination}
export PATH=$PATH:/usr/local/go/bin
...

ตัวอย่าง project go

  • Create Project
$ mkdir golang
$ cd golang
  • Create file main.go
package main

import "fmt"

func main() {
	fmt.Printf("What's up ? , GO \n")
}

  • Run
$ go run main.go
What's up ? , GO 
  • Build & Run
$ go build main.go
$ ./main.go
What's up ? , GO

อ้างอิงจาก :

A Tour of Go เรียนรู้การใช้ภาษา Go ใน 15 นาที Getting Started - The Go Programming Language