14 minute read

Tags:

課程主題

  • Go 基礎語法介紹
    • 命名常規
    • 分號規則
    • 變數宣告
    • 何謂零值
    • 常數
    • 遞增常數 (iota)
    • 流程控制
    • 指標
    • 陣列與切片(Slice)
    • 雜湊表(map)
    • 延遲執行
    • panic vs error
  • Go 型別系統
    • 內建型別(built-in type)
    • 參考型別(reference type)
    • 結構型別(struct type)
    • Method 與 receiver
      • Pointer receiver
      • Value receiver
    • 型別內嵌(Type Embedding)
    • 標籤(tag)
    • 介面
    • 字串深入剖析
    • 別名(Alias)
  • Go package
    • 生命週期介紹
    • 命名常規
    • internal package
  • Go module
    • 語意化版本(semantic versioning)
    • 初始化 go module
    • 認識 go module 相關檔案 -go.mod -go.sum
    • 認識 go.mod directive
    • 常用 go mod 指令
  • Gin 網頁開發框架
    • 何謂 multiplexer
    • 何謂 handler
    • Gin engine 介紹
    • 路由機制
    • 資料繫節(data binding)
    • 資料驗證(data validation)
    • 使用 Middleware
    • 啟用 Swagger
  • 使用 GORM 操作資料庫
    • 資料庫連線概念說明
    • GORM the ORM library 簡介
    • Auto Migration -常用資料庫 tag 介紹
    • 使用 GORM 操作 CRUD
  • 部署 Go 應用程式
    • 如何部署 Go 開發的網站
    • 發佈 CLI 工具的注意事項

Go 的原因

code 優點 缺點
C++ 執行速度快 型別安全 編譯慢 語法複雜
Java 編譯快 型別安全 生態系統複雜
Python 容易使用 缺少型別安全 執行速度較慢

Go 沒有執行序的概念(Goroutines) 底層一定是用 thread BUT 語言概念沒有唷!

Go Standard Lib.

Go Cli

Go 跨平台

Go 只有 25 個 關鍵字!

break        default      func         interface    select
case         defer        go           map          struct
chan         else         goto         package      switch
const        fallthrough  if           range        type
continue     for          import       return       var

猜猜關鍵字

package main

import "fmt"

func main () {
	var true bool = false
	fmt.Println(true) // false

	var int string = "str"
	fmt.Println(int) // str

	var bool int32 = 123
	fmt.Println(bool) // 123
}

在 go 中 true false 是變數唷!!!

  • 原始碼

     // true and false are the two untyped boolean values.
     const (
     	true  = 0 == 0 // Untyped bool.
     	false = 0 != 0 // Untyped bool.
     )
    

誰使用 Go

Json-to-Go

Go 抓 data and 掃出來

  • json-to-go 超酷!!!!! 知道 json 樣貌後 可以幫你趴 struct !!
package main

import (
	"encoding/json"
	"fmt"
	"net/http"
)

type AutoGenerated struct {
	Result struct {
		Limit   int    `json:"limit"`
		Offset  int    `json:"offset"`
		Count   int    `json:"count"`
		Sort    string `json:"sort"`
		Results []struct {
			Info      string `json:"info"`
			Stitle    string `json:"stitle"`
			XpostDate string `json:"xpostDate"`
			Longitude string `json:"longitude"`
			REFWP     string `json:"REF_WP"`
			AvBegin   string `json:"avBegin"`
			Langinfo  string `json:"langinfo"`
			MRT       string `json:"MRT"`
			SERIALNO  string `json:"SERIAL_NO"`
			RowNumber string `json:"RowNumber"`
			CAT1      string `json:"CAT1"`
			CAT2      string `json:"CAT2"`
			MEMOTIME  string `json:"MEMO_TIME"`
			POI       string `json:"POI"`
			File      string `json:"file"`
			Idpt      string `json:"idpt"`
			Latitude  string `json:"latitude"`
			Xbody     string `json:"xbody"`
			ID        int    `json:"_id"`
			AvEnd     string `json:"avEnd"`
			Address   string `json:"address"`
		} `json:"results"`
	} `json:"result"`
}

func main() {
	resp, err := http.Get("https://data.taipei/api/v1/dataset/36847f3f-deff-4183-a5bb-800737591de5?scope=resourceAquire&limit=10&fbclid=IwAR08alf9h64Hv8ZVMZFW6ZXeO3h0eNQ0P9hy-0uhp8GVIFjscMu_xyNa5J8")
	if err != nil {
		return
	}
	defer resp.Body.Close()

	var data AutoGenerated // 宣告就占住記憶體位置!
	err = json.NewDecoder(resp.Body).Decode(&data)
	if err != nil {
		return
	}
	for _, v := range data.Result.Results {
		fmt.Println(v.Address)
	}
}


Go 不是 OOP 沒有物件的概念! 沒有 Object 所有東西都是 Value !!!

  • Value : 記憶體中的某一格

  • 在 Go 中 只有 struct ! 沒有 class!
  • 一個 struct 就是一個 memory layout
    • 記憶體中每一格可以放什麼 在宣告的時候就存在了!
    •   type data struct {
            Name string `json:"name"`
            Age int `json:"age"`
        }
      
        var user data // == var user = data{}
      
  • 在 Go 中沒有空值 只有 zero value
  • Struct 就是會佔住 記憶體位置!




Go 基礎語法

  • 自動加分號規則
    • an identifier
    • an integer, floating-point, imaginary, rune, or string literal
    • one of the keywords break, continue, fallthrough, or return
    • one of the operators and punctuation ++, –, ), ], or }
  • Naming Convention

    • package names:
      • 全部小寫
      • 不准用 -
      • 只有 測試程式 才會用(_) 當 package name
      • package name 一定 要等於資料夾名稱!!!
    • Getters/Setters
      • Go Get 通常不會加入 Get ex: t.Owner()
      • Go Set 加入 Set ex:t.SetOwner(user)
    • Interface names:
      • 通常命名 用 er 結尾, ex: Writer, Reader
    • MixedCaps:
      • 用駝峰命名
    • 命名大小寫:
      • 小 私有
      • 大 公開
  • 宣告

     var i = "G is" + " for Go "
     var j = 'V'
     var k1, k2 = true, !k1
     const l = 111*100000 + 9
     const m1 = math.Pi / 3.141592
    
     var (
     name string = "Earth"
     desc string = "Planet"
     radius int32 = 6378
     mass float64 = 5.972E+24
     active bool = true
     satellites []string
     )
    
  • Zero Value
類別 Zero Value
string ””
byte, int, int8, int16, int32, int64, rune, uint, uint8, uint16, uint32, uint64,uintptr, float32,float64 0
bool 0!=0
interface, func, chan, slice, map, *pointer nil
  • 宣告常數const(僅可使用基礎型別)

    • 數字: byte, int, int8, int16, int32, int64, rune, uint, uint8, uint16, uint32, uint64, uintptr, float32, float64, complex64, complex128
    • 布林: bool
    • 字串 string
       const (
           a = 5
           b  // 5
           c  // 5
           d  // 5
       )
    
    • untyped const

       const (
           PI = 3.1415
       ) 
            
       func main() {
         var diameter float64 = 5.2
         circumference := diameter * PI
         ...
       }
      
    • iota 遞增常數

       const (
           Zero = iota // 0
           One         // 1
           Two         // 2
           Three       // 3
           Four        // 4
       )
    
       const (
           p2_0 = 1 << iota // 2^0 = 1
           _
           p2_2 // 2^2 = 4
           _
           p2_4 // 2^4 = 16
       )
    
      package main
        
      import (
      	"fmt"
      	"time"
      )
        
      const (
      	Sunday time.Weekday = iota
      	Monday
      	Tuesday
      	Wednesday = 20
      	Thursday = iota * 2
      	Friday
      	Saturday
      )
        
      func main() {
      	fmt.Println(Tuesday) // Tuesday
      	fmt.Println(Wednesday) // 20
      	fmt.Println(Saturday) // 12
      }
    
  • if statement

if err := req.ParseForm(); err != nil {
    log.Println(err)
}
  • Switch Statements + fallthrough

    • 跟其他語言不同 Go switch/case 不需要 break, 預設就會 break
    • 如果要繼續 加入 fallthrough
     currency := "NTD"
     switch currency {
     case "JPY":
        fmt.Println("JPY is valid")
     case "NTD":
        fmt.Println("NTD is valid")
        fallthrough
     case "USD":
        fmt.Println("USD is valid")
     case "HKD":
        fmt.Println("XY HKD valid")
     }
    
  • Switch statements + 判斷條件

     currency := "NTD"
     switch {
     case currency == "JPY":
        fmt.Println("JPY is valid")
     case currency == "NTD" || currency == "USD":
        fmt.Println("NTD and USD is valid")
     }
    
  • Swtich statements + interface

     func findAny(val interface{}) {
        switch i := val.(type) {
           case int:
           fmt.Printf("It's int. %d", i)
           case string:
           fmt.Printf("It's string. %s", i)
           }
     }
    
  • for statements

     for x < 10 {
         ...
     }
    
     for {
         ...
     }
    
     for i := 0; i < 0; i ++ {
         ...
     }
    
     values := [2]string{"NTD", "USD"}
     for i, val := range values {
     fmt.Println(i, val)
     }
    
     values := [2]string{"NTD", "USD"}
     for index := range values {
     fmt.Println(index)
     }
    
     for k:= 0, k < 10; {
         ...
     }
    
     for ; k < 10 ; {
         ...
     } 
    
     for ;; {
         ...
     }
    
     for {
         ...
     }
    
  • func 回傳多個值

     func GetScore() (int, string){
        score, comment := 95, "high score"
        return score, comment
     }
    
     func Divide(a, b float32) (res float32, err error) {
        if b == 0 {
           err = errors.New(" 0")
           return
        }
        return a / b, nil
     }
    
     Sum(1, 2, 3, 4, 5)
     Sum([]int{1, 2, 3, 4, 5}...)
       
     func Sum(args ...int) (sum int){
         for _, val := range args {
             sum += val
         }
         return
     }
    
  • Integer literals

     int_lit        = decimal_lit | binary_lit | octal_lit | hex_lit .
     decimal_lit    = "0" | ( "1"  "9" ) [ [ "_" ] decimal_digits ] .
     binary_lit     = "0" ( "b" | "B" ) [ "_" ] binary_digits .
     octal_lit      = "0" [ "o" | "O" ] [ "_" ] octal_digits .
     hex_lit        = "0" ( "x" | "X" ) [ "_" ] hex_digits .
       
     decimal_digits = decimal_digit { [ "_" ] decimal_digit } .
     binary_digits  = binary_digit { [ "_" ] binary_digit } .
     octal_digits   = octal_digit { [ "_" ] octal_digit } .
     hex_digits     = hex_digit { [ "_" ] hex_digit } .
    

基礎語法練習

  • 1
     const (
         first = iota
         second
         third = 9
         fourth
     )
     const (
         fifth = iota
         sixth
     )
     func main() {
         println(first, second, third, fourth, fifth, sixth) // 0, 1, 9, 9. 0, 1
     }
    
  • 2

     func main() {
         var a int = 10
         var b int = 0B0111
         sum := a + b 
         println(sum) // 17
     }
    
  • 3

     const (
         a = 2 << iota // 2^0
         b
         c
     )
     func main() {
         println(a, b, c) // 0, 4, 8
     }
    
  • 4

     func main() {
         for i := 0; i < 3; {
             println(i)
         }
     }
     // 印出 0 的 無群迴圈!!
    
  • 5

     func main() {
         name := "John"
       
         {
             name := "Bob"
             fmt.Println(name)
         }
       
         fmt.Println(name)
       
         {
             name = "Kevin"
             fmt.Println(name)
         }
       
         fmt.Println(name)
     }
     // Bob, John, Kevin, Kevin
    

基礎語法: 陣列與切片

  • Array & Slice

  • Array 長度不可變

     weekdays := [...]string{
     "Monday",
     "Tuesday",
     "Wednesday",
     "Thursday",
     "Friday",
     }
    
     var days [7]string = [7]string{
     "Monday",
     "Tuesday",
     "Wednesday",
     "Thursday",
     "Friday",
     "Saturday",
     "Sunday",
     }
    
  • Slice
    • 一定有一個相對實際的陣列在記憶體中
    • Slice 有三個重要屬性(The Slice header)
      • a pointer
        • Slice 起始位置指向陣列的一個元素(a poiner to the starting pointer of underlying array)
      • len
        • 切片長度
      • cap
        • 可使用的陣列長度
    • slice 初始化
       weekdays := [] string{"Mon", "Tue", "Wed", "Thu", "Fri"}
    
       var days [5]string = [5]string{"Mon", "Tue", "Wed", "Thu", "Fri"}
       days2 := days[0:7] // days[:]
    
      make([]T, len, cap)
      months := make([]sting, 6, 6)
    
    • ex:
      weekdays := []string{"Mon", "Tue", "Wed", "Thu", "Fri"}
      q1 := weekdays[0: 3] // len=3, cap=5
      q2 := weekdays[3:]   // len=2, cap=2
    
  • 練習 Slice

      1. 種點 切邊 arr[2:7] –> 2, 3, 4, 5, 6 不包含駔後一個唷~
         func main() {
             arr := [10]int{1, 2, 3, 4, 5}
             slice := arr[2: 7]
             fmt.Println(len(slice), cap(slice), slice)
             // 5, 8, [3, 4. 5. 0, 0]
         }
      
      1. slice()
         s := []int{8, 3, 5, 1, 2, 4, 6, 9 , 7, 10}
         sort.Slice(s, func(i, j int) bool { return s[i] < s[j] })
      
  • 使用 append 擴充 slice 容量

     slice := []int{10, 20, 30, 40}
       
     newSlice := append(slice, 50)
    
     package main
       
     import "fmt"
       
     func main() {
     	temCap := 0
     	var b []int
     	for i := 0; i < 99999; i++ {
     		if temCap != cap(b) {
     			temCap = cap(b)
     			fmt.Println(cap(b))
     		}
     		b = append(b, i)
     	}
     }
    
  • copy(dst, src)
func main(){
    a6 := []int{-10, 1, 2, 3, 4, 5}
    a4 := []int{-1, -2, -3, -4}
    copy(a6, a4)
    // [-1, -2, -3, -4, 4, 5]
}
func main() {
       a6 := []int{-10, 1, 2, 3, 4, 5}
    a4 := []int{-1, -2, -3, -4}
    copy(a4, a6)
    // [-10, 1, 2, 3]
}
  • 合併
w1 := []string{"Mon", "Tue"}
w2 := []string{"Wed", "Thu", "Fri"}

w1 = append(w1, w2...)
  • 強化觀念
package main

import "fmt"

func main() {
	w1 := make([]string, 2, 10)
	w1[0] = "Mon"
	w1[1] = "Tue"
	w2 := []string{"Wed", "Thu", "Fri"}

	w3 := append(w1, w2...)

	fmt.Println(w1)
	fmt.Println(w3)
}
// 總共 2 array, len(w1): 2, len(w2): 3, len(w3): 5 cap(w3): 10
  • 寫一個 func 傳入 slice (s1) return slice (s2)

    • 修改 s2 不影響 傳入的 s1 slice
      • b[0] = 100
      • a[0] = 1
package main

import "fmt"

func main() {
	var a = []int{1, 2, 3}
	var b = CopySlice(a)
	b[0] = 100
	a[0] = 1
	fmt.Println(a, b)
	fmt.Println(b[0])
	fmt.Println(a[0])
}

func CopySlice(input []int) []int{
	copySlice := make([]int, len(input), len(input))
	copy(copySlice, input)
	return copySlice
}

func CopySlice2(input []interface{}) []interface{}{
    // a[low: high: max]
	return append(input[0:0:0], input...)
}
  • Slice Expressions

    • a[low: high: max]
  • slice 練習

     package main
       
     import "fmt"
       
     func main() {
     	// exercise 1
         weedays := []string{"Mon", "Tue", "Wed", "Thu", "Fri"}
       
         w1 := weedays[:3]
         w2 := weedays[3:]
       
         w1 = append(w1, "XXX")
         fmt.Println("[exercise 1]: ", w2)
       
         // exercise 2
         // 請把 arr2 的 7 個人名,加入 arr1 的 slice 中 (請貼上程式碼)
     	arr1 := []string{"Adams", "Arthur", "Buchanan", "Bush", "Carter", "Cleveland", "Clinton", "Coolidge", "Eisenhower"}
     	arr2 := []string{"Hayes", "Hoover", "McKinley", "Roosevelt", "Taft", "Taylor", "Wilson"}
     	arr1 = append(arr1, arr2...)
     	fmt.Println("[exercise 2] arr1: ", arr1)
       
         // exercise 3
         // 請把 5 拿掉  arr := []int{1, 2, 3, 4, 5, 6, 7, 8, 9, 10} 變成 => arr => []int{1, 2, 3, 4, 5, 7, 8, 9, 10}
         arr := []int{1, 2, 3, 4, 5, 6, 7, 8, 9, 10}
         exercise3 := append(arr[:5], arr[6:]...)
     	fmt.Println("[exercise 3]: ", exercise3)
       
         // exercise 4
         // 把 exercise 3 改成 func
     	arr4 := []int{1, 2, 3, 4, 5, 6, 7, 8, 9, 10}
     	exercise3Result := sliceIndex(arr4, 5)
         fmt.Println("[exercise 4]: ", exercise3Result)
     }
       
     func sliceIndex(input []int, index int) (result []int) {
     	return append(input[:index], input[index+1:]...)
     }
    

雜湊表

  • map
    • map[<key type>] <value type>
    • reference type 初始值是 nil
     m := make(map[string]string)
     m["Red"] = "#FF0000"
     m["Lime"] = "#00FF00"
     value := m["Red"]
    
     m := map[string]string{
     "Red": "#FF0000",
     "Lime": "#00FF00",
     }
     value := m["Red"]
    
    • 判斷 map kwy 是否存在
       value, exists := m["Blue"]
       if exist {
           ...
       }
    
  • 可用 key type

    • boolean
    • number(integer, float, complex)
    • stuct
    • array
  • 刪除 map 的 key

     m := map[string]int{"Will": 10}
     value, exists := m["Will"]
     fmt.Println(value, exists) // 10, true
     delete(m, "Will")
     value, exists = m["Will"]
     fmt.Println(value, exists) // 0, false
    
  • 在 func 之間傳遞 map 的注意事項

    • Passing a map between two functions doesn’t make a copy of the map.
    • In fact, you can pass a map to a function and make changes to the map, and the changes will be reflected by all references to the map.

延遲執行 恐慌與復原

  • defer

    • LIFO 先進先出
    • 方法區塊結束執行
    
       func main() {
       conn, err := amqp.Dial("amqp://guest:guest@localhost:5672/")
       failOnError(err, "Failed to connect to RabbitMQ")
       defer conn.Close()
       ch, err := conn.Channel()
       failOnError(err, "Failed to open a channel")
       defer ch.Close()
       ...
       }
        // ch.Close() ---> conn.Close()
    
  • panic

    • 發生 panic 會立刻執行 defer 的方法
    • 如果沒有處裡 則 panic 最終會傳到 main 導致城市停止運行
  • defer & recover

     defer func() {
         if r := recover(); r != nil {
             ...
         }
     }()
     ...
     panic("panic test2")
     ...
       
    
     package main
       
     import "fmt"
       
     func main(){
     	panicMachine()
     }
       
     func panicMachine(){
     	defer func(){
     		if r := recover(); r != nil {
     			fmt.Println(r)
     		}
     	}()
     	panic("GG 拉!!")
     }
    
    • 顯示錯誤
        errors.New("GG 拉~~~")
    

Go 型別系統 (三種型別)

  • Is Go an object-oriented language

  • Built-in-types ALWAYS: Pass by value !!!

    • string
    • bool
    • number
      • byte, int, int8, int16, int32, int64, rune, uint, uint8, uint16, uint32, uint64, uintptr, float32, float64, complex64, complex128
  • Reference types Pass by header value

    • slice, map, interface(不能實體化 只能宣告型別), func
    • zero value 是 nil

    • 初始化
      • slice
        • s := make([]byte, 10)
      • map
        • m := make(map[string]string)
      • chan
        • c := make(chan, int, 10)
      • func
        • var f = func(){}
    • 定義 interface 型別

          type Writer interface {
              Write(p []byte) (n int, err error)
          }
      
  • Struct types

    • 有序的欄位集合, 欄位可以是 built-in types, reference types, 或 struct types

    • init

    
      package main
    
        import "fmt"
          
        type User struct {
        	ID int
        	Name string
        }
          
        func main(){
        	var u User
        	u2 := User{ 01, "Tim"}
        	fmt.Printf("u: %#+v\n", u)
        	fmt.Printf("u: %#+v\n", u2)
        }
    
    • 匿名 struct 型別

       var msg = struct {
           Name string 
           Message string 
           Number init
       }{ 
           Name: "Will",
           Message: "hello",
           Number: 123,
       }
       fmt.Println(msg.Name) // Will
      
  • 定義任意型別

    • type myType ini

       type Handler func(c Context)
       type Open func(c Context) error
       type Output func(c Context) (int, error)
       type Type int
       type Code string
       type H map[string]interface{}
       type C chan int
      
  • 定義型別的應用技巧

      package main
        
      import "time"
        
      type Weekday int
        
      const (
      	Sunday Weekday = iota
      	Monday
      	Tuesday
      	Wednesday
      	Thursday
      	Friday
      	Saturday
      )
        
      func main(){
         var aDay int = 3
         var today2 Weekday = Weekday(aDay)
         var today3 Weekday = 3
         today4 := Weekday(3)
      }
    

指標

  • 指標使用範例
    • & 取得記憶體位置
      • dereference 解開指標
     func main() {
         var a int = 10
         var p *int = &a
         fmt.Println(a, p, *p)
         Modify(p)
         fmt.Println(a, p, *p)
     }
       
     func Modify(v *int){
         *v = 99
     }
    
     type User struct {
        Id int
        Name string
     }
     func main() {
        var user *User = NewUser(10, "doggy")
        fmt.Println(user)
     }
     func NewUser(id int, name string) *User {
        return &User{Id: id, Name: name}
     }
    
  • 關於 * 的兩種意義與用法

    • 當 * 與型別一起使用
      • 宣告為指標型別 (Pointer Type)
      • 其值必須為記憶體位址
      • 可透過 & 取得變數的記憶體位址
    • 當 * 與變數一起使用
      • 用來取得指標所指向的值
      • dereference a pointer
     package main
       
     import "fmt"
       
     func main() {
     	var a int = 10
     	p := &a
     	fmt.Println(*p) // 10
     	fmt.Println(p)  // 0xc000000a0c0
     }
     	*p = 99
    
      fmt.Println(*p) // 99
      fmt.Println(p)  // 0xc000000a0c0
      fmt.Println(a)  // 99
    

只要不是用指標 就是把資料 copy 一份完整的內容過去!

  • 範例1
func main() {
var a int = 10
var p *int = &a
// a = 10
fmt.Println("a = ", a)
// address of a = 0xc00018ccc0
fmt.Println("address of a = ", &a)
// p = 0xc00018ccc0
fmt.Println("p = ", p)
// address of p = 0xc0000cac28
fmt.Println("address of p = ", &p)
// dereferenced value of p = 10
fmt.Println("dereferenced value of p = ", *p)
}
  • 範例2
package main

import "fmt"

func main(){
	a := 10
	p := &a
	p2 := &p

	fmt.Println(a, p, p2) // 10 0xc00000a0c0 0xc000006028
	fmt.Println(p2)       // 0xc000006028
	fmt.Println(*p2)      // 0xc00000a0c0
	fmt.Println(**p2) // 10
}
  • pointer 練習
package main

import "fmt"

func main() {
	// exercise 1
	i := 5
	pi := &i
	*pi--
	square(pi)
	fmt.Println("i: ", i) // 16
	// exercise 2
	a := 20
	p1 := &a
	p2 := &p1
	fmt.Println(**p2) // 20
	// exercise 3
	a3 := 10
	p3 := &a3
	*p3 = 99
	fmt.Println(a3, *p3) // 99, 99
	// exercise 4
	a4 := 10
	p4 := &a4
	b4 := 20
	p4 = &b4
	fmt.Println(a4, *p4) // 10 20

}

func square(n *int) {
	*n = *n * *n
}

Web Api

  • net/http 建立 Web 服務
package main
import "net/http"
func main() {
   mux := http.NewServeMux()
   mux.HandleFunc("/home", index)
server := http.Server{
   Addr: ":8080",
   Handler: mux,
}
   server.ListenAndServe()
}
func index(w http.ResponseWriter, r *http.Request) {
   w.Write([]byte("Hello Web"))
}
  • 寫法一

     package main
     import "net/http"
     func main() {
        // Multiplexer
        mux := http.NewServeMux()
        mux.HandleFunc("/home", index)
        http.ListenAndServe(":8080", mux)
     }
     func index(w http.ResponseWriter, r *http.Request) {
        w.Write([]byte("Hello Web"))
     }
    
  • 寫法二(簡化)

     package main
     import "net/http"
     func main() {
        http.HandleFunc("/home", index)
        // 用預設 multiplexer
        http.ListenAndServe(":8080", nil)
     }
     func index(w http.ResponseWriter, r *http.Request) {
        w.Write([]byte("Hello Web"))
     }
    
  • 安裝 gin

    • go get -u github.com/gin-gonic/gin
  • ex:

package main

import (
	"api.homework.yuting/model"
	"encoding/json"
	"github.com/gin-gonic/gin"
	"net/http"
)

func main(){

	router := gin.Default()

	router.GET("/emp", func(c *gin.Context){
		data, err := GetJson()
		if err != nil {
			return
		}
		c.JSON(http.StatusOK, data)
	})
    router.Run(":8080")
}


func GetJson() (a *model.Travel, err error) {
	resp, err := http.Get("https://data.taipei/api/v1/dataset/36847f3f-deff-4183-a5bb-800737591de5?scope=resourceAquire&limit=10&fbclid=IwAR08alf9h64Hv8ZVMZFW6ZXeO3h0eNQ0P9hy-0uhp8GVIFjscMu_xyNa5J8")
	if err != nil {
		return
	}
	defer resp.Body.Close()

	err = json.NewDecoder(resp.Body).Decode(&a)
	if err != nil {
		return
	}
	return a, nil
}   

回家作業說明

實作主題

霹靂布袋戲角色資料庫系統

事前準備

  • 請使用事先建立好的 Go 專案範本進行開發

實作目標

請利用 gin 實作五個 RESTful APIs

  • 取得全部資料 [GET] http://localhost:8080/role
  • 新增單筆資料 [POST] http://localhost:8080/role
  • 取得單筆資料 [GET] http://localhost:8080/role/:id
  • 更新單筆資料 [PUT] http://localhost:8080/role/:id
  • 刪除單筆資料 [DELETE] http://localhost:8080/role/:id

實作方式

請直接利用 slice 管理資料集合,無須透過資料庫存取!

JSON-to-Go

Tags:

Updated: