《Go圣经》章四:复合数据类型

参考书《Go程序设计语言》Go学习路径的Go基础模块,整理了一些我掌握不太好的地方

数组和结构体都是聚合类型,他们的值由内存中的一组变量构成。数组元素相同,结构体元素可以不同,他们的长度都是固定的。slice和map都是动态数据结构,他们的长度随着元素的添加动态增长。

  1. 数组

    • 在数组字面量中,如果省略号…出现在数组长度的位置,那么数组的长度由初始化的数组的元素个数决定。

      q := [...]int{1,2,3}
      fmt.Println("%T\n",q)	//"[3]int"
      
    • 数组的长度是数组类型的一部分,[3]int和[4]int是两种不同的数组类型,数组的长度必须是常量表达式,在编译时就确定。

      q := [3]int{1,2,3}
      q = [4]int{1,2,3,4}	//编译错误
      
    • 上面是按顺序给出一组值,也可以给出索引和索引对应的值,这样索引可以以任意顺序出现,还可以省略,省略的会被赋为零值。

      type Currency int
      const (
      	USD Currency = iota
          RMb
      )
      symbol := [...]string{USD:"$",RMB:"¥"}
      fmt.Println(RMB,symbol[RMB]) //"3 ¥"
      
      r := [...]int{99:-1}	//第100个-1,其余0
      
    • 如果一个数组的元素类型是可比较的,那么这个数组也是可比较的。

      a := [2]int{1,2}
      b := [...]int{1,2}
      c := [2]int{1,3}
      fmt.Println(a==b,a==c,b==c)	//"true false false"
      d := [3]int{1,2}
      fmt.Println(a==d)	//编译错误
      
    • 当调用函数时,传入的参数会创建一个副本,然后赋值给对应的函数变量,所以函数接受的是一个副本而不是原始的参数。这种方式在传递大数组的时候会很低效。这种情况下,go把数组和其他类型都看成值传递,而在其他语言中,数组是隐式的使用引用传递。

      也可以显示传递一个数组的指针,这样在函数内部对数组的任何修改都会反映到原始数组上面。

      func zero(ptr *[32]byte) {
          /*for i := range ptr {
              ptr[i] = 0
          }*/
          *ptr = [32]byte{}
      }
      
  2. slice

    • slice表示拥有相同类型元素的可变长度序列,通常写成[]T,数组和slice是紧密关联的,slice可以访问数组的部分或全部的元素,而这个数组成为slice的底层数组。

    • slice有三个属性:指针,长度,容量。指针指向数组的第一个可以从slice访问的元素,长度指slice元素个数,它不能超过容量,容量的大小通常是从slice的起始元素到底层数组最后一个元素间的元素个数。

    • 一个底层数组可以对应多个slice,这些slice可以引用数组任何位置,彼此还可重叠。

      months := [...]string{1:"January",...,12:"December"}
      
      summer := months[6:9] "6,7,8"
      endlessSummer := summer[:5] "6,7,8,9,10"
      
    • 初始化slice不指定长度,创建指向数组的slice。和数组不同,slice无法比较,但可以使用bytes.Equal来比较两个字节slice,但对于其他类型slice需要自己写函数比较。slice允许和nil比较,值为nil的slice没有对应的底层数组

      s := []int{1,2,3,4,5}

    • 内置函数make可以创建一个具有指定元素类型,长度,容量的slice,其中容量参数可以省略,这种情况下容量等于长度。

      make([]T,len)
      make([]T,len,cap) //等同于make([]T,cap)[:len]
      

      其实make是创建了一个无名数组并返回了它的一个slice,这个数组仅可以通过这个slice访问,容量就是数组的长度。

    • append函数

      var x []int
      x = append(x,1)
      x = append(x,2,3)
      x = append(x,4,5,6)
      ...
      fmt.Println(x)	//"[1,2,3,4,5,6]"
      

      当容量不足时,会创建一个新的数组并指向它。

  3. map

    • go语言中,map是散列表的引用。内置函数make创建一个map:

      ages := make(map[string]int)

    • 也可以使用map字面量。

      ages := map[string]int {
          "alice":31,
          "charlie":34,
      }
      //等价于
      ages := make(map[string]int)
      ages["alice"] = 31
      ages["charlie"] = 34
      
    • 可以使用内置函数delete移除一个元素。

      delete(ages,"alice")

    • 如果map中没有某个键,使用时返回类型零值。

      ages["bob"] = ages["bob"] + 1
      ages["bob"] += 1
      ages["bob"]++ 	//三者等价
      
    • map元素不是一个变量,无法获取地址,因为map的可增长性导致每一个元素的地址是动态的,这样就可能使获得的地址无效。

    • map中元素迭代是无序的,如果需要按照某种顺序遍历map中的元素,必须显式的给键排序,也就是拿个切片存键,对切片排序,再通过切片遍历键值。

  4. 结构体

    • 聚合类型不可以包含他自己,但是命名结构体中可以定义一个它的指针,这样我们可以创建一些递归数据结构,比如链表和树。

      type tree struct {
          value int
          left,right *tree	//二叉树
      }
      
    • 结构体类型的值可以通过结构体字面量设置,即通过设置结构体的成员变量来设置。

      type Point struct {X,Y int}
      p := Point{1,2}
      q := Point{X:1,Y:2}
      
    • 由于结构体都是通过指针的方式使用,因此可以使用一种简单的方式创建初始化一个struct类型的变量并获取他的地址。

      pp := &Point{1,2}
      //等价于:
      pp := new(Point)
      *pp = Point{1,2}
      
    • 如果结构体所有变量成员都可以比较,那么这个结构体也可以使用或者!=比较,其中按照顺序比较成员变量,可比较的结构体可以作为map的键类型。

      p := Point{1,2}
      q := Point{2,1}
      fmt.Println(p.X == q.X && p.Y == q.Y) //"false"
      //等价于:
      fmt.Println(p == q)  //"false"
      
    • Go允许定义不带名称的结构体成员,只需要指定类型即可,这种结构体成员称作匿名成员,匿名成员必须是一个命名类型或命名类型的指针。

      type Point struct {
          X,Y int
      }
      type Circle struct {
          Point
          Radius int
      }
      type Wheel struct {
          Circle
          Spokes int
      }
      
      var w wheel
      w.X = 8			//等价于w.Circle.Point.X = 8
      w.Y = 8			//等价于w.Circle.Point.Y = 8,如果是circle,point那么在包外不能这么用
      w.Radius = 5	//等价于w.Circle.Radius = 5
      w.Spokes = 20
      
      //但是不能这么干:
      w = Wheel{8,8,5,20}	//编译错误,未知成员变量
      w = Wheel{X:8,Y:8,Radius:5,Spokes:20}	//编译错误,未知成员变量
      
      //可以这样:
      w = Wheel{Circle{Point{8,8},5},20}
      //或者这样
      w = Wheel{
          Circle:Circle{
              Point:Point{X:8,Y:8},
              Radius:5,	//逗号必须有
          },
          Spokes:20,	//逗号必须有
      }
      
      fmt.Printf("%#v\n",w)
      //"Wheel{Circle:Circle{Point:Point{X:8,Y:8},Radius:5},Spokes:20}"
      //%#v格式带着X:,Y:这些东西
      
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
Go语言圣经》是一本广受好评的教材,旨在帮助读者系统地学习和掌握Go语言。这本书以简明清晰的方式介绍了Go语言的各种特性、语法和用法,是入门和进阶者的理想选择。 首先,该书提供了对Go语言基础知识的全面介绍。它从简单到复杂地解释了Go语言的基本概念,诸如变量、函数、循环和条件语句等等。通过丰富的例子和练习,读者能够逐步理解和掌握这些概念。 其次,该书详细介绍了Go语言的高级特性和用法。读者可以学习到Go语言的面向对象编程、并发编程、网络编程等关键技术。并发编程是Go语言的一个独特特性,对于提高程序性能和扩展能力非常重要。 此外,该书还包含了对常见问题和陷阱的讲解,帮助读者避免一些常见的错误和陷阱。同时,书中提供了大量的案例和实践项目,读者可以通过实际操作来巩固所学内容。 《Go语言圣经》以其简洁明了的风格和对细节的深入讲解而闻名。无论是作为初学者的入门指南,还是作为有经验的开发者的参考书,这本书都能满足读者的需求。此外,该书的PDF版本能够方便地在线或离线阅读,为读者提供了更加便捷的学习体验。 综上所述,《Go语言圣经》是一本内容丰富、权威性强的优秀教材。它不仅适合Go语言的初学者,也适用于那些想要深入学习和掌握Go语言的开发者。无论是在线阅读还是PDF版本,读者都能够方便地获取和利用这本宝贵的学习资源。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值