顯示具有 Golang 標籤的文章。 顯示所有文章
顯示具有 Golang 標籤的文章。 顯示所有文章

對稱密鑰加密:進階加密標準(Advanced Encryption Standard,AES)

https://zh.wikipedia.org/wiki/%E9%AB%98%E7%BA%A7%E5%8A%A0%E5%AF%86%E6%A0%87%E5%87%86


Should I use ECB or CBC encryption mode for my block cipher?

https://crypto.stackexchange.com/questions/225/should-i-use-ecb-or-cbc-encryption-mode-for-my-block-cipher

Never use ECB! It is insecure.

I recommend an authenticated encryption mode, like EAX or GCM. If you can't use authenticated encryption, use CBC or CTR mode encryption, and then apply a MAC (e.g., AES-CMAC or SHA1-HMAC) to the resulting ciphertext.


Golang 實現 AES encryption with GCM:


C 語言、Golang 各是如何定義「函數」的

https://segmentfault.com/a/1190000016329960

在 C、C++ 等 C 兼容的語言中,函數通常是一組指令的集合,這組指令的入口地址可以用函數名稱取得。

但是在 Go 語言中,函數是一種類型,而且是第一類型 (first-class),它的地位和 int、string 等類型是一樣的。

在 Golang,我們可以聲明一個值類型為某個函數的變量,這種類型叫做函數變量,也就是說,函數可以被當作一個值類型賦值給變量。

Golang: Slice (切片) 的 copy 函數

https://stackoverflow.com/questions/30182538/why-cant-i-duplicate-a-slice-with-copy

The builtin copy(dst, src) copies min(len(dst), len(src)) elements.

So if your dst is empty (len(dst) == 0), nothing will be copied.

Try tmp := make([]int, len(arr)) (Go Playground):

Unfortunately this is not documented in the builtin package, but it is documented in the Go Language Specification: Appending to and copying slices:

The number of elements copied is the minimum of len(src) and len(dst).

Edit:

Finally the documentation of copy() has been updated and it now contains the fact that the minimum length of source and destination will be copied:

Copy returns the number of elements copied, which will be the minimum of len(src) and len(dst).

複製返回複製的元素數量,該數量將是len(src)和len(dst)的最小值。


測試:https://play.golang.org/p/Q1KmOtE2rR5

Golang: 清空 slice 的兩種方法

https://play.golang.org/p/tk31HADdMxA

letters := []string{"a", "b", "c", "d"}

letters = nil
// 清空後 cap 值清零、len 值清零

letters = letters[:0]
// 清空後 cap 值和之前相同、len 值清零

Golang: 數字型態


uint8  : 0 ~ 255
uint16 : 0 ~ 65535
uint32 : 0 ~ 4294967295
uint64 : 0 ~ 18446744073709551615
int8   : -128 ~ 127
int16  : -32768 ~ 32767
int32  : -2147483648 ~ 2147483647
int64  : -9223372036854775808 ~ 9223372036854775807
整數預設型態: int

https://play.golang.org/p/GRpIOgxZafU


https://blog.cyeam.com/json/2017/12/18/go-int-size

int is a signed integer type that is at least 32 bits in size. It is a distinct type, however, and not an alias for, say, int32.

uint is a variable sized type, on your 64 bit computer uint is 64 bits wide.

int 與 uint 是根據 CPU 是 32位元 或 64位元 變化的。

若查看 strconv.Itoa 的原始碼,會發現

const host32bit = ^uint(0)>>32 == 0

使用了 int 長度的特性來判斷是否為 32位元

https://play.golang.org/p/Or99SPVNbm


JSON and Go

https://mgleon08.github.io/blog/2019/02/17/golang-json-and-go/

Encoding - Marshal 序列化

在 Go 中並不是所有的類型都能進行序列化:
  • 必須是 struct 中支援外部引用的 field 才能夠序列化 (即開頭字母大寫的 field)
  • JSON object key 只支援 string
  • Channel、complex、function 等 type 無法進行序列化
  • 不支援循環數據結構,因為序列化時會進行無限迴圈
  • Pointer 序列化之後是其指向的值或者是 nil
1
func Marshal(v interface{}) ([]byte, error)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
package main

import (
  "encoding/json"
  "fmt"
)

type UserInfo struct {
  Name string
  Say  string
  Age int64
}

func main() {
  m := UserInfo{"Leon", "Hello", 18}
  b, _ := json.Marshal(m)
  fmt.Println(string(b))
}

// {"Name":"Leon","Say":"Hello","Age":18}

指定 JSON filed name

Struct Tag

Struct tag 可以決定 Marshal 和 Unmarshal 函式如何序列化和反序列化數據。
  • 一般 json 都是小寫,但因為 golang 序列化時,struct 必須是大寫,因此透過 Struct Tag 改成小寫
  • mongodb 則是使用 bson,可以在 struct 加上 json:"name,omitempty" bson:"name,omitempty"
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
package main

import (
  "encoding/json"
  "fmt"
)

type UserInfo struct {
  Name string `json:"name"`
  Say  string `json:"say"`
  Age int64   `json:"age"`
}

func main() {
  m := UserInfo{"Leon", "Hello", 18}
  b, _ := json.Marshal(m)
  fmt.Println(string(b))
}

// {"name":"Leon","say":"Hello","age":18}

指定 field 的行為

omitempty

透過 omitempty 如果 field 的值是對應類型的 zero-value,序列化之後的 JSON object 中不包含此 field
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
package main

import (
  "encoding/json"
  "fmt"
)

type UserInfo struct {
  Name string `json:"name"`
  Say  string `json:"say"`
  Age int64   `json:"age,omitempty"`
}

func main() {
  m := UserInfo{}
  b, _ := json.Marshal(m)
  fmt.Println(string(b))
}

// {"name":"","say":""}

-

透過 - 可以忽略掉該 field
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
package main

import (
  "encoding/json"
  "fmt"
)

type UserInfo struct {
  Name string `json:"name"`
  Say  string `json:"-"`
  Age int64   `json:"age,omitempty"`
}

func main() {
  m := UserInfo{"Leon", "Hello", 18}
  b, _ := json.Marshal(m)
  fmt.Println(string(b))
}

// {"name":"Leon","age":18}

Decoding - Unmarshal 反序列化

預設的 JSON 支援以下幾種 Go 類型:
1
2
3
4
bool for JSON booleans
float64 for JSON numbers
string for JSON strings
nil for JSON null

知道類型的反序列化

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
package main

import (
  "encoding/json"
  "fmt"
)

type UserInfo struct {
  Name string `json:"name"`
  Say string  `json:"say"`
  Age int64   `json:"age"`
}

func main() {
  var jsonString string
  jsonString = `{"name":"Leon","say":"hello","age":18}`
  
  //把 json unmarshal 進去 struct
  u := &UserInfo{}
  err := json.Unmarshal([]byte(jsonString), u)
  if err != nil {
      fmt.Println(err)
      return
  }
  fmt.Println(u)
  fmt.Printf("%T\n", u)
  fmt.Printf("name:%s, say:%s, age:%d\n", u.Name, u.Say, u.Age)
}

// &{Leon hello 18}
// *main.UserInfo
// name:Leon, say:hello, age:18

不知道類型的反序列化

如果不知道類型可以用 interface{}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
package main

import (
  "encoding/json"
  "fmt"
)

func main() {
  var jsonString string
  jsonString = `{"name":"Leon","age":18,"cars":["Maserati","BMW"]}`
  
  //把 json unmarshal 進去 struct
  var u interface{}
  err := json.Unmarshal([]byte(jsonString), &u)
  if err != nil {
      fmt.Println(err)
      return
  }
  fmt.Println(u)
  fmt.Printf("%T\n", u)
}

// map[cars:[Maserati BMW] name:Leon age:18]
// map[string]interface {}
回傳的格式如
1
2
3
4
5
6
7
8
map[string]interface{}{
    "Name": "Leon",
    "age":  18,
    "cars": []interface{}{
        "Maserati",
        "BMW",
    },
}
key 是 string,value 是 interface{},必須透過 type assertion 和 range 取得所有的 key
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
package main

import (
  "encoding/json"
  "fmt"
)

func showInfo(u interface{}){
  m := u.(map[string]interface{})
  for k, v := range m {
      switch vv := v.(type) {
      case string:
          fmt.Println(k, "is string", vv)
      case float64:
          fmt.Println(k, "is float64", vv)
      case []interface{}:
          fmt.Println(k, "is an array:")
          for i, u := range vv {
              fmt.Println(i, u)
          }
      default:
          fmt.Println(k, "is of a type I don't know how to handle")
      }
  }
}

func main() {
  var jsonString string
  jsonString = `{"name":"Leon","age":18,"cars":["Maserati","BMW"]}`

  //把 json unmarshal 進去 struct
  var u interface{}
  err := json.Unmarshal([]byte(jsonString), &u)
  if err != nil {
      fmt.Println(err)
      return
  }
  showInfo(u)
}

// name is string Leon
// age is float64 18
// cars is an array:
// 0 Maserati
// 1 BMW

Reference Types - 反序列化對 slice、map、pointer 的處理

struct 中包含一個 slice Cars ,slice 預設是 nil,之所以反序列化可以正常進行就是因為 Unmarshal 在序列化時進行了對 slice Cars 做了初始化,同理,對 map 和 pointer 都會做類似的工作
比如序列化如果 Pointer 不是 nil 首先進行 dereference 獲得其指向的值,然後再進行序列化,反序列化時首先對 nil pointer 進行初始化
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
package main

import (
    "encoding/json"
    "fmt"
)

type UserInfo struct {
    Name string
    Age  int64
    Cars []string
}

func main() {
    var jsonString string
    jsonString = `{"name":"Leon","age":18,"cars":["Maserati","BMW"]}`

    //把 json unmarshal 進去 struct
    u := &UserInfo{}
    err := json.Unmarshal([]byte(jsonString), u)
    if err != nil {
        fmt.Println(err)
        return
    }
    fmt.Println(u)
    fmt.Printf("%T\n", u)
    fmt.Printf("name:%s, age:%d, cars:%s\n", u.Name, u.Age, u.Cars)
}

// &{Leon 18 [Maserati BMW]}
// *main.UserInfo
// name:Leon, age:18, cars:[Maserati BMW]

nested struct 的序列化

Go 支援對 nested struct 進行序列化和反序列化:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
package main

import (
    "encoding/json"
    "fmt"
)

type App struct {
  Id string `json:"id"`
}

type Org struct {
  Name string `json:"name"`
}

type AppWithOrg struct {
  App
  Org
}

func main() {
  data := []byte(`{ "id": "123", "name": "My Awesome Org" }`)
  var b AppWithOrg
  json.Unmarshal(data, &b)
  fmt.Printf("%#v\n\n", b)
  
  a := AppWithOrg{
      App: App{ Id: "321" },
      Org: Org{ Name: "My Awesome Org"},
  }
  data, _ = json.Marshal(a)
  fmt.Println(string(data))
}

// main.AppWithOrg{App:main.App{Id:"123"}, Org:main.Org{Name:"My Awesome Org"}}
// {"id":"321","name":"My Awesome Org"}

Stream JSON

Golang 提供 Decoder 和 Encoder 對 stream JSON 進行處理,常見 request 中的 Body、文件等
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
package main

import (
  "encoding/json"
  "fmt"
  "io"
  "log"
  "strings"
)

func main() {
  const jsonStream = `
  {"Name": "Ed", "Text": "Knock knock."}
  {"Name": "Sam", "Text": "Who's there?"}
  {"Name": "Ed", "Text": "Go fmt."}
  {"Name": "Sam", "Text": "Go fmt who?"}
  {"Name": "Ed", "Text": "Go fmt yourself!"}
`
  type Message struct {
      Name, Text string
  }
  dec := json.NewDecoder(strings.NewReader(jsonStream))
  for {
      var m Message
      if err := dec.Decode(&m); err == io.EOF {
          break
      } else if err != nil {
          log.Fatal(err)
      }
      fmt.Printf("%s: %s\n", m.Name, m.Text)
  }
}

// Ed: Knock knock.
// Sam: Who's there?
// Ed: Go fmt.
// Sam: Go fmt who?
// Ed: Go fmt yourself!
參考文件


程式語言編年史

程式語言編年史原文 下面這張圖片描繪了整個程式語言的歷史。包括各種程式語言的發明人、程式語言的特點和適用領域、被什麼網站或公司使用等 (檢視 完整高清圖 )。 之所以會有那麼多不同的程式語言是因為設計程式語言的初衷不同、對語言學習曲線的追求不同、不同程式之間的執行成本差異...