Introduction of GoLang Johnny Sung 圖片來源:https://www.gctel.com/gopher-bounty-match-program/
Full stack developer Johnny Sung (宋岡諺) https://fb.com/j796160836 https://blog.jks.co ff ee/ https://www.slideshare.net/j796160836 https://github.com/j796160836
https://www.facebook.com/ProgrammersCreateLife/photos/a.962151813833697/5879918952056934/
App ⼯程師都做些什麼? •拉 UI 畫⾯ (Zeplin, Figma) •接 API (Swagger) •⼿機特殊功能 (例如:藍芽、相機...) •修 Bug
接 API •Swagger •API Testing
Go 語⾔介紹 Golang 是 2007 年由 Google 設計的,2009 年對外公開 主要⽬的是簡化軟體開發並提⾼效率。 它在設計上強調簡單性、易讀性和⾼性能, 特別適合編寫低延遲的後端服務和分佈式系統。
Why Go ? •強型別 (strongly typed) •靜態型別 (statically typed) •垃圾回收 (garbage collection) •平⾏運算、並⾏性 •體積⼩、效能快、多平台
Why Go ? https://www.docker.com/company/newsroom/media-resources/ https://kubernetes.io/ 都是使⽤ Go 語⾔編寫的
GoLand by JetBrains IDE https://www.jetbrains.com/go/
伺服器架構 •後端程式 •資料庫 •共享空間 •排程器 (Queue)
程式架構 •Data Model •商業邏輯 •DB Interface, HTTP Interface
Go 語⾔特性
:= 短變數宣告 (Stort variable declaration) 變數建立 + 賦值 (assign) 的簡寫 package main import "fmt" func main() { var a int = 3 b := 3 fmt.Println(a) fmt.Println(b) }
https://twitter.com/cachecoherent/status/1539867862227091456 指標(pointer)
指標 (pointer) package main import "fmt" func main() { var a int = 3 var p *int = &a fmt.Println(a) fmt.Println(&a) fmt.Println(p) fmt.Println(&p) fmt.Println(*p) } // 3 // 0x14000124008 // 0x14000124008 // 0x14000126018 // 3 (印出值) (印該變數記憶體位址) (印出儲存的位址) (印該變數記憶體位址) (存取指標印出值)
Array(陣列) & Slice(切⽚) •Array(陣列):固定⻑度 (Fixed length) 的清單 •Slice(切⽚):可以⾃由增加或減少⻑度的清單 (常⽤)
#include <stdio.h> #include <stdlib.h> int main() { int *arr; int i; arr = malloc( 10 * sizeof(int) ); for (i = 0; i < 10; i++) { arr[i] = i; } for (i = 0; i < 10; i++) { printf("%d ", arr[i]); } free(arr); return 0; } package main import "fmt" func main() { var arr [10]int for i := 0; i < 10; i++ { arr[i] = i } for i := 0; i < 10; i++ { fmt.Printf("%d ", arr[i]) } } Golang C Array(陣列)
Slice(切⽚) https://pjchender.dev/golang/slice-and-array/
for 搭配 range package main import "fmt" func main() { var arr = []int{46, 15, 73, 16, 66, 35} for index, value := range arr { fmt.Printf("%d ", index, value) } }
Class(類別) •Go 語⾔沒有 class (類別) 只有 struct (結構) type Car struct { Brand string Year int }
type Car struct { Brand string Year int } func (p *Car) SetBrand(brand string) { p.Brand = brand } func (p *Car) SetYear(year int) { p.Year = year } func (p *Car) GetBrand() string { return p.Brand } func (p *Car) GetYear() int { return p.Year } public class Car { private String brand; private int year; public Car(String brand, int year) { this.brand = brand; this.year = year; } public void setBrand(String brand) { this.brand = brand; } public void setYear(int year) { this.year = year; } public String getBrand() { return brand; } public int getYear() { return year; } } Golang Java
接收器 讓 struct 有擴充 method 的可能 •值接收器 (value receiver) •指標接收器 (point receiver)
接收器 •值接收器 (value receiver) 它會複製 struct 變數並傳進函式 (method) func (c Car) GetName() int { return c.Name }
•指標接收器 (point receiver) 它會把 struct 轉成指標並傳進函式 (method) [常⽤] 接收器 func (p *Car) SetYear(year int) { p.Year = year }
func (p *Car) SetYear(year int) { p.Year = year } func (p *Car) SetYear(year int) { (*p).Year = year } 同義 ⾃動解除參照(語法糖) type Car struct { Brand string Year int }
Error package main import ( "fmt" "strconv" ) func main() { v = "s2" s2, err := strconv.Atoi(v) if err != nil { fmt.Println(err) // strconv.Atoi: parsing "s2": invalid syntax } fmt.Printf("%T, %vn", s2, s2) // int, 0 } Atoi (string to int)
Error package main import ( "fmt" "strconv" ) func main() { v := "10" s, err := strconv.Atoi(v) if err != nil { fmt.Println(err) } fmt.Printf("%T, %vn", s, s) // int, 10 } Atoi (string to int)
defer(推遲、延後) (⽰意簡化版範例) package main import ( "fmt" "os" ) func main() { userFile := "my_file.txt" fout, err := os.Create(userFile) if err != nil { fmt.Println(userFile, err) return } defer fout.Close() fout.WriteString("Hello, World.") }
channel(通道) package main import "fmt" func main() { ch := make(chan int, 1) defer close(ch) ch <- 1 fmt.Print(<-ch) } var ch chan int ch = make(chan int) ch := make(chan int) 宣告 塞值、取值 fatal error: all goroutines are asleep - deadlock! 緩衝區為 1 channel 型態
多執⾏緒 & WaitGroup package main import ( "fmt" "sync" ) func main() { wg := sync.WaitGroup{} wg.Add(2) go func() { defer wg.Done() // Do something }() go func() { defer wg.Done() // Do something }() wg.Wait() fmt.Println("Done") } package main import ( "fmt" "sync" ) func main() { wg := sync.WaitGroup{} wg.Add(2) go worker(&wg) go worker(&wg) wg.Wait() fmt.Println("Done") } func worker(wg *sync.WaitGroup) { defer wg.Done() // Do something }
(async () => { await Promise.all([ (async () => { console.log('Worker 1 started'); await sleep(1000); console.log('Worker 1 finished'); })(), (async () => { console.log('Worker 2 started'); await sleep(2000); console.log('Worker 2 finished'); })(), ]); console.log('Done'); })(); async function sleep(ms) { return new Promise(resolve => setTimeout(() => resolve(), ms)); } package main import ( "fmt" "sync" "time" ) func main() { wg := sync.WaitGroup{} wg.Add(2) go func() { defer wg.Done() fmt.Println("Worker 1 started") time.Sleep(time.Millisecond * 1000) fmt.Println("Worker 1 finished") }() go func() { defer wg.Done() fmt.Println("Worker 2 started") time.Sleep(time.Millisecond * 2000) fmt.Println("Worker 2 finished") }() wg.Wait() fmt.Println("Done") } Golang JavaScript (NodeJS)
channel(通道) package main import "fmt" func main() { ch := make(chan int) defer close(ch) ch <- 1 fmt.Print(<-ch) } fatal error: all goroutines are asleep - deadlock! ⚠ 無緩衝區
https://decomyplace.com/n.php?id=9357 ch := make(chan int, 1)
https://www.dnaindia.com/business/report-what-s-cooking-on-the-cloud-2752364
https://static.wixstatic.com/media/160302bd324b4187b67b7f265c3b8f24.jpg/v1/ fi ll/w_541,h_1333,al_c,q_85,enc_auto/160302bd324b4187b67b7f265c3b8f24.jpg ? to ch <- 1 fatal error: all goroutines are asleep - deadlock!
⽤ range 讀取 channel •⽤ range 讀取 channel 直到它被關閉 ,若無值可取就會「等待」 •channel 關閉後,進⼊ 唯讀 狀態 •for range 會讀完 所有值 才結束 ch := make(chan int) // ... do something for i := range ch { fmt.Println(i) }
https://blog.xuite.net/yafenyan/blog/60585613#
Fan out / Fan in https://betterprogramming.pub/writing-better-code-with-go-concurrency-patterns-9bc5f9f73519
package main import ( "fmt" "sync" "time" ) func main() { res := distributedSum(4, 1, 100) fmt.Printf("Total: %dn", res) } Fan out / Fan in 範例
func distributedSum(numOfWorkers int, from int, to int) int { wg := &sync.WaitGroup{} wg.Add(numOfWorkers) in := make(chan int, (to-from)-1) out := make(chan int, numOfWorkers) res := make(chan int, 1) for i := 0; i < numOfWorkers; i++ { go sumWorker(in, out, wg) } go compilationWorker(out, res) for i := 0; i <= to; i++ { in <- i // 塞資料給各個 sumWorkers } close(in) // 關閉資料窗⼝ (通知各個 sumWorkers 停⽌讀值) wg.Wait() // 等待所有 workers 結束 close(out) // 關閉資料窗⼝ (通知 compilationWorker 停⽌讀值) return <-res }
func sumWorker(in chan int, out chan int, wg *sync.WaitGroup) { defer wg.Done() num := 0 for n := range in { // 讀取通道直到通道被關閉 num += n time.Sleep(time.Millisecond * 30) } fmt.Printf("partial sum: %dn", num) out <- num } func compilationWorker(in chan int, out chan int) { sum := 0 for i := range in { // 讀取通道直到通道被關閉 sum += i } out <- sum }
•完全⾃學!Go 語⾔ (Golang) 實戰聖經 (The Go Workshop: Learn to write clean, efficient code and build high-performance applications with Go) https://www.tenlong.com.tw/products/9789863126706 •下班加減學點 Golang 與 Docker https://ithelp.ithome.com.tw/users/20104930/ironman/2647 •被選召的 Gopher 們,從零開始探索 Golang, Istio, K8s 數碼微服務世界 https://ithelp.ithome.com.tw/articles/10240228 •PJCHENder 未整理筆記 https://pjchender.dev/golang/go-getting-started/ 參考資料
Mobile API CRUD Login / Logout Token (Session) JWT / Clean Architecture Unit Test Docker Kubernetes (k8s) Load Balancer Database Cache Queue Swagger channel mutex lock CI / CD MongoDB RDBMS MySQL PostgreSQL Memcached Redis RabbitMQ grafana + prometheus Pod Service Ingress SOLID 5 OOP 3 goroutine Backup DRP (Disaster Recovery Plan) Logs BCP (Business Continuity Plan) Git Logger
obile API CRUD Login / Logout Token (Session) JWT / Clean Architecture Unit Test Docker Kubernetes (k8s) Swagger channel mutex lock Pod Service Ingress SOLID 5 OOP 3 goroutine
Mobile Token (Session) JWT Docker Kubernetes (k8s) Load Balancer Database Cache Queue Swagger MongoDB RDBMS MySQL PostgreSQL Memcached Redis RabbitMQ Pod Service Ingress Logger
Mobile CI / CD grafana + prometheus Backup DRP (Disaster Recovery Plan) Logs BCP (Business Continuity Plan) Git
Q & A

[Golang] 以 Mobile App 工程師視角,帶你進入 Golang 的世界 (Introduction of GoLang)