简述

基本类型是Go语言世界的原子,复合类型则是分子。

数组

数组是固定长度的序列。因此,其很少直接使用。 与C语言数组特性类似。

    var a [3]int    //其中[3]int为数组类型
    fmt.Println(a[0])
    fmt.Println(a[len(a) - 1])

    var b [3]int = [3]int{1, 2, 3}
    var c [3]int = [3]int{1, 2}
    var d = [...]int{1, 2, 3, 4}    // len = 4
    q := [...]int{1, 2}

    //指定一个索引和对应值列表的方式初始化
    type Currency int
    const (
        USD Currency = iota // 美元
        EUR // 欧元
        GBP // 英镑
        RMB // 人民币
    )
    symbol := [...]string{USD: "$", EUR: "€", GBP: "£", RMB: "¥"}
    fmt.Println(RMB, symbol[RMB]) // "3 ¥"

    r := [...]{99: -1}  //第100个元素初始化为-1

如果两个数组类型可以比较,那么两个数组是可以用==或!=比较

    a := [...]int{1, 2}
    b := [...]int{1, 2, 3}
    c := [...]int{1, 2}
    d := [...]int{1, 1}

    fmt.Println(a == b)     //err: [2]int与[3]int数组类型不同
    fmt.Println(a == c)     //true
    fmt.Println(a == d)     //false

数组用于函数参数,由于数组长度的固定性。一般不用于函数参数。

    //清零数组
    func zero(ptr *[32]byte) {
        *ptr = [32]byte{}
    }
    // zero函数不能接受[16]byte类型的指针

切片(Slice)

  1. 基本概念

构成: 指针、长度和容量 指针为Slice第一个元素地址,并不一定是数组第一个元素地址 len和cap分别返回长度和容量,len(slice) <= cap(slice)

    months := [...]string{1: "January", /* ... */, 12: "December"}
    months[1:13]    //引用12个月份
    months[1:]      //引用12个月份
    months[:]       //引用整个数组,0和12个月份
  1. Slice作为函数参数
    func reverse(s []int) {
        for i, j := 0, len(s) - 1; i < j; i++, j-- {
            s[i], s[j] = s[j], s[i]
        }
    }

    a := [...]int{1, 2, 3, 4, 5}
    reverse(a)  //error, must be Slice.
    reverse(a[:])
  1. Slice不能进行==或!=比较
  2. slice唯一合法的比较操作是和nil比较
    var s []int // len(s) == 0, s == nil
    s = nil // len(s) == 0, s == nil
    s = []int(nil) // len(s) == 0, s == nil
    s = []int{} // len(s) == 0, s != nil
  1. 判断Slice是否为空,需要用len(s) == 0判断
  2. Slice创建和追加元素
    make([]T, len)
    make([]T, len, cap) // same as make([]T, cap)[:len]

    s := make([]int, 5)
    s = append(s, 1)
    s = append(s, 2)
    fmt.Println(s)

  1. Slice 追加 Slice
    s1 := []int{1, 2, 3, 4}
    s2 := []int{5}

    s2 = append(s2, s1...)
  1. 切片插入元素
    func insertSlice(s []interface{}, pos int, value interface{}) []interface{} {
        rear := append([]interface{}{}, s[pos:]...)
        s = append(s[:pos], value)
        s = append(s, rear...)
        fmt.Printf("addr-s: %p\n", s)
  
        return s
  }

Map

与cpp中的unordered_map类似,Go中的map底层也是哈希表 map[K]V中的K必须是支持==运算符的数据类型 符点数用作K是一个糟糕的用法,符点数具有精度问题。

  1. map创建
    //使用make创建
    ages := make([string]int)
    //字面值创建
    ages := map[string]int{
        "alice": 31,
        "charlie": 34,
    }
    //创建空map
    ages := map[string]int {}
    //遍历
    for name, age := range ages {
        fmt.Printf("%s\t%d\n", name, age)
    }
    fmt.Println(ages["alice"])
    fmt.Println(ages["Lily"]) //不存在的key,返回对应类型的0值

    /////nil
    var ages map[string]int
    fmt.Println(ages == nil) // "true"
    fmt.Println(len(ages) == 0) // "true"

    //判断key是否存在
    age, ok := ages["Lucy"]
    if !ok {
        //not exists
    }
    //简写
    if age, ok := ages["Lucy"]; !ok {
        /////////
    }
  1. map的零值为nil
  2. map之间不能进行==或!=比较,只能和nil比较
  3. Map的value类型也可以是一个聚合类型
  4. 不支持 == 操作的不能作为 map key:如 slice、function、map

结构体

  1. 相邻成员如果类型相同,可以合并到同一行
    type Employee struct {
        ID int
        Name, Address string
        DoB time.Time
        Position string
        Salary int
        ManagerID int
    }
  1. 没有任何成员的结构体是空结构体,表示为struct{}, 其默认零值为struct{}{}
  2. 结构体字面值
    //方法一,较小的结构体中使用
    type Point struct {
        x, y int
    }

    p := Point{1, 2}

    //方法二,通用型
    type T struct {
        a, b int
    }

    t := T{a: 2, b: 3}
  1. 作为函数参数和返回值
    type Point struct {
        x, y int
    }

    func Scale(p Point, factor int) Point {
        return Point{p.x * factor, p.y * factor}
    }

    //对于较大结构体或为了改变成员的值,需要用结构体指针作参数
    func Scale(p *Point, factor int) {
        p.x *= factor
        p.y *= factor
    }
  1. 两个结构体可以用==或!=进行比较
    type Point struct {
        x, y int
    }

    p := Point{x: 1, y: 2}
    q := Point{x: 2, y: 1}
    fmt.Println(p == q) //false
  1. 匿名成员

匿名成员必须是命名类型或命名类型指针 外层结构体获得匿名成员的所有成员和可导出方法

    type Point struct {
        x, y int
    }

    type Circle struct {
        Point
        Radius int
    }

    type Wheel struct {
        Circle
        Spokes int
    }

    var w Wheel
    w.x = 1
    w.y = 2
    w.Radius = 3
    w.Spokes = 5

    //字面值表示
    w = Wheel{Circle{Point{8, 8}, 5}, 20}
    w = Wheel{
        Circle: Circle{
            Point: Point{X: 8, Y: 8},
            Radius: 5,
        },
        Spokes: 20, // NOTE: trailing comma necessary here (and at Radius)
    }

    w = Wheel{1, 2, 3, 5} //compile error

JSON

  1. marshaling(编码): 将结构体Slice转为json字符串的过程
  2. unmarshaling(解码): 将json字符串转为结构体Slice的过程
    type Movie struct {
        Title string
        Year int `json:"released"`
        Color bool `json:"color,omitempty"`
        Actors []string
    }
    var movies = []Movie{
        {Title: "Casablanca", Year: 1942, Color: false,
        Actors: []string{"Humphrey Bogart", "Ingrid Bergman"}},
        {Title: "Cool Hand Luke", Year: 1967, Color: true,
        Actors: []string{"Paul Newman"}},
        {Title: "Bullitt", Year: 1968, Color: true,
        Actors: []string{"Steve McQueen", "Jacqueline Bisset"}},
        // ...
    }

    //编码
    data, err := json.Marshal(movies)   //或MarshalIndent产生缩进json字符串
    if err != nil {
    log.Fatalf("JSON marshaling failed: %s", err)
    }
    fmt.Printf("%s\n", data)

    //解码
    var titles []struct{ Title string }     //获取部分json内容
    if err := json.Unmarshal(data, &titles); err != nil {
        log.Fatalf("JSON unmarshaling failed: %s", err)
    }
    fmt.Println(titles) // "[{Casablanca} {Cool Hand Luke} {Bullitt}]"

文本和HTML模板

//…