3_Structs_Slices_and_Maps

  • 指针

    (1) 类型 *T 是指向 T 类型值的指针,其零值为 nil

      var p *int
    

    (2) & 操作符会生成一个指向其操作数的指针

      i := 42
      p = &i
    

    (3) * 操作符表示指针指向的底层值

      fmt.Println(*p) // 通过指针 p 读取 i
      *p = 21         // 通过指针 p 设置 i
    
      package main
    
      import "fmt"
    
      func main() {
    
          i, j := 42, 2701
    
          p := &i         // 指向 i
          fmt.Println(*p) // 通过指针读取 i 的值
          *p = 21         // 通过指针设置 i 的值
          fmt.Println(i)  // 查看 i 的值
    
          p = &j         // 指向 j
          *p = *p / 37   // 通过指针对 j 进行除法运算
          fmt.Println(j) // 查看 j 的值
      }
    
  • 结构体struct

    (1) 一个结构体(struct)就是一组字段(field)

    (2) 结构体字段使用点号.来访问

      package main
    
      import "fmt"
    
      type Vertex struct {
          X int
          Y int
      }
    
      func main() {
    
          v := Vertex{1, 2}
          v.X = 4
          fmt.Println(v.X)
      }
    

    (3) 结构体字段也可以通过结构体指针来访问,即(*p).X,但是实际用p.X访问也支持

      package main
    
      import "fmt"
    
      type Vertex struct {
    
          X int
          Y int
      }
    
      func main() {
    
          v := Vertex{1, 2}
          p := &v
          p.X = 1e9
          fmt.Println(v)
      }
    

    (4) 结构体__文法__

    通过直接列出字段的值来新分配一个结构体,使用 Name: 语法可以仅列出部分字段,未列出字段被隐式赋予

      package main
    
      import "fmt"
    
      type Vertex struct {
          X, Y int
      }
    
      var (
          v1 = Vertex{1, 2}  // 创建一个 Vertex 类型的结构体
          v2 = Vertex{X: 1}  // Y:0 被隐式地赋予
          v3 = Vertex{}      // X:0 Y:0
          p  = &Vertex{1, 2} // 创建一个 *Vertex 类型的结构体(指针)
      )
    
      func main() {
    
          fmt.Println(v1, p, v2, v3)
      }
    
  • 数组

    (1) 类型 [n]T 表示拥有 n 个 T 类型的值的数组

    (2) 数组的长度是其类型的一部分,因此__数组不能改变大小__

      package main
    
      import "fmt"
    
      func main() {
    
          var a [2]string
          a[0] = "Hello"
          a[1] = "World"
          fmt.Println(a[0], a[1])
          fmt.Println(a)
    
          primes := [6]int{2, 3, 5, 7, 11, 13}
          fmt.Println(primes)
      }
    
  • 切片

    (1) []T 表示一个元素类型为 T 的切片

    (2) 切片则为数组元素提供动态大小的、灵活的视角

    (3) 切片通过两个下标来界定,即一个上界和一个下界,二者以冒号分隔:a[low : high],包括low不包括high

      package main
    
      import "fmt"
    
      func main() {
    
          primes := [6]int{2, 3, 5, 7, 11, 13}
    
          var s []int = primes[1:4]
          fmt.Println(s)
      }
    

    (4) 切片本身不保存数据,只是__数组的引用__。所以同一数组上的所有切片或数组自身的元素修改,会被所有相关切片和数组本身观测到

      package main
    
      import "fmt"
    
      func main() {
    
          names := [4]string{"John", "Paul", "George", "Ringo"}
          fmt.Println(names)
    
          a := names[0:2]
          b := names[1:3]
          fmt.Println(a, b)
    
          b[0] = "XXX"
          fmt.Println(a, b)
          fmt.Println(names)
      }
    

    (5) 切片文法

    [3]bool{true, true, false}会创建一个数组;

    []bool{true, true, false}会创建一个数组(但是没有名字),然后创建一个指向它全部数组元素范围的切片

    (6) 切片的__默认下界是0__,默认上界是数组长度,可以省略下界和上界,此时采用的就是默认值

      对于数组var a [10]int来说,以下切片是等价的:
    
      a[0:10]
      a[:10]
      a[0:]
      a[:]
    

    (7) 切片的__长度len__和__容量cap__

    1° 切片的__长度__就是它所包含的元素个数。

    2° 切片的__容量__是从它的第一个元素开始数,到其底层数组元素末尾的个数

    3° 切片 s 的长度和容量可通过表达式 len(s) 和 cap(s) 来获取

      package main
    
      import "fmt"
    
      func main() {
    
          s := []int{2, 3, 5, 7, 11, 13}
          printSlice(s)
    
          // 截取切片使其长度为 0
          s = s[:0]
          printSlice(s)
    
          // 拓展其长度
          s = s[:4]
          printSlice(s)
    
          // 舍弃前两个值
          s = s[2:]
          printSlice(s)
      }
    
      func printSlice(s []int) {
    
          fmt.Printf("len=%d cap=%d %v\n", len(s), cap(s), s)
      }
    

    (8) 切片的零值是__nil__

    然而数组的零值不是nil,数组和struct一样,零值是内部元素的零值集合

    (9) 切片可以用内建函数 make 来创建,make 函数会分配一个元素为零值的数组并返回一个引用了它的切片

      package main
    
      import "fmt"
    
      func main() {
    
          a := make([]int, 5)
          printSlice("a", a)
    
          b := make([]int, 0, 5)
          printSlice("b", b)
    
          c := b[:2]
          printSlice("c", c)
    
          d := c[2:5]
          printSlice("d", d)
      }
    
      func printSlice(s string, x []int) {
    
          fmt.Printf("%s len=%d cap=%d %v\n", s, len(x), cap(x), x)
      }
    

    (10) go语言中__数组很少使用,绝大多数情况都是用切片__

    (11) 切片可以包括任何类型,可以创建切片的切片

      package main
    
      import (
          "fmt"
          "strings"
      )
    
      func main() {
    
          // 创建一个井字板(经典游戏)
          board := [][]string{[]string{"_", "_", "_"}, []string{"_", "_", "_"}, []string{"_", "_", "_"}, }
    
          // 两个玩家轮流打上 X 和 O
          board[0][0] = "X"
          board[2][2] = "O"
          board[1][2] = "X"
          board[1][0] = "O"
          board[0][2] = "X"
    
          for i := 0; i < len(board); i++ {
              fmt.Printf("%s\n", strings.Join(board[i], " "))
          }
      }
    

    (12) 向切片追加元素–append

      package main
    
      import "fmt"
    
      func main() {
    
          var s []int
          printSlice(s)
    
          // 添加一个空切片
          s = append(s, 0)
          printSlice(s)
    
          // 这个切片会按需增长
          s = append(s, 1)
          printSlice(s)
    
          // 可以一次性添加多个元素
          s = append(s, 2, 3, 4)
          printSlice(s)
      }
    
      func printSlice(s []int) {
          fmt.Printf("len=%d cap=%d %v\n", len(s), cap(s), s)
      }
    

    (13) for 循环的 range 形式可遍历切片或映射

    当使用 for 循环遍历切片时,每次迭代都会返回__两个值__。第一个值为当前元素的__下标__,第二个值为该下标所对应元素的__一份副本__

      package main
    
      import "fmt"
    
      var pow = []int{1, 2, 4, 8, 16, 32, 64, 128}
    
      func main() {
    
          for i, v := range pow {
              fmt.Printf("2**%d = %d\n", i, v)
          }
      }
    

    可以将下标或值赋予 _ 来__忽略__它。

      for i, _ := range pow
      for _, value := range pow
    

    若你只需要索引,忽略第二个变量即可。

      for i := range pow
    
  • 映射map

    (1) 作用:将键映射到值

    (2) 映射的零值为 nil

    (3) make 函数会返回给定类型的映射,并将其__初始化__备用

      package main
    
      import "fmt"
    
      type Vertex struct {
          Lat, Long float64
      }
    
      var m map[string]Vertex
    
      func main() {
    
          m = make(map[string]Vertex)
          m["Bell Labs"] = Vertex{40.68433, -74.39967, }
          fmt.Println(m["Bell Labs"])
      }
    

    (4) 映射的文法(和struct用法差不多)

      package main
    
      import "fmt"
    
      type Vertex struct {
    
          Lat, Long float64
      }
    
      var m = map[string]Vertex{
          "Bell Labs": Vertex{40.68433, -74.39967,},
          "Google": Vertex{37.42202, -122.08408,},
      }
    
      func main() {
          fmt.Println(m)
      }
    

    若顶级类型只是一个类型名,你可以在文法的元素中省略它

    (5) 在映射 m 中插入或修改元素

      m[key] = elem
    

    (6) 获取元素

      elem = m[key]
    

    (7) 删除元素

      delete(m, key)
    

    (8) 通过双赋值检测某个键__是否存在__

      elem, ok := m[key]
    

    若 key 在 m 中,ok 为 true ;否则,ok 为 false。

    若 key 不在映射中,那么 elem 是该映射元素类型的零值

  • 函数值

    (1) 函数值可以用作函数的__参数__或__返回值__

      package main
    
      import (
          "fmt"
          "math"
      )
    
      func compute(fn func(float64, float64) float64) float64 {
    
          return fn(3, 4)
      }
    
      func main() {
    
          hypot := func(x, y float64) float64 {
              return math.Sqrt(x*x + y*y)
          }
    
          fmt.Println(hypot(5, 12))
    
          fmt.Println(compute(hypot))
          fmt.Println(compute(math.Pow))
      }
    

    (2) 函数的__闭包__

    Go 函数可以是一个闭包。闭包是一个函数值,它引用了其函数体之外的变量。该函数可以访问并赋予其引用的变量的值

      package main
    
      import "fmt"
    
      func adder() func(int) int {
    
          sum := 0
    
          return func(x int) int {
              sum += x
              return sum
          }
      }
    
      func main() {
    
          pos, neg := adder(), adder()
    
          for i := 0; i < 10; i++ {
      
              fmt.Println(pos(i), neg(-2*i),)
          }
      }
    
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值