《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
    评论
项目:使用 JavaScript 编写的杀死幽灵游戏(附源代码) 杀死鬼魂游戏是使用 Vanilla JavaScript、CSS 和 HTML 画布开发的简单项目。这款游戏很有趣。玩家必须触摸/杀死游荡的鬼魂才能得分。您必须将鼠标悬停在鬼魂上 - 尽量得分。鬼魂在眨眼间不断从一个地方移动到另一个地方。您必须在 1 分钟内尽可能多地杀死鬼魂。 游戏制作 这个游戏项目只是用 HTML 画布、CSS 和 JavaScript 编写的。说到这个游戏的特点,用户必须触摸/杀死游荡的幽灵才能得分。游戏会根据你杀死的幽灵数量来记录你的总分。你必须将鼠标悬停在幽灵上——尽量得分。你必须在 1 分钟内尽可能多地杀死幽灵。游戏还会显示最高排名分数,如果你成功击败它,该分数会在游戏结束屏幕上更新。 该游戏包含大量的 javascript 以确保游戏正常运行。 如何运行该项目? 要运行此游戏,您不需要任何类型的本地服务器,但需要浏览器。我们建议您使用现代浏览器,如 Google Chrome 和 Mozilla Firefox。要玩游戏,首先,单击 index.html 文件在浏览器中打开游戏。 演示: 该项目为国外大神项目,可以作为毕业设计的项目,也可以作为大作业项目,不用担心代码重复,设计重复等,如果需要对项目进行修改,需要具备一定基础知识。 注意:如果装有360等杀毒软件,可能会出现误报的情况,源码本身并无病毒,使用源码时可以关闭360,或者添加信任。
javascript 中的 Paint War Game 是使用 HTML、CSS 和 JavaScript 开发的。谈到游戏玩法,这款游戏的主要目标是建造比敌人更多的油漆砖。您所要做的就是使用 WASD 键输入玩家的动作。您可以使用 VS Code 来运行该项目。 关于项目 每次您的玩家走过一块瓷砖时,它都会被涂成您的团队颜色。您必须在同一块瓷砖上走 4 次才能获得更多游戏点数。瓷砖会被您的团队挡住,并且不能再被偷走。如果您走过另一支球队的瓷砖,它会像您第一次走过时一样被涂上颜色。如果您创建一个封闭的被阻挡瓷砖图形,图形内所有未被阻挡的瓷砖都将固定为您的团队颜色。这个游戏充满乐趣,创造和重新即兴发挥会更有趣。 要运行此项目,我们建议您使用现代浏览器,例如 Google Chrome、  Mozilla Firefox。该游戏可能还支持 Explorer/Microsoft Edge。 演示: javascript 中的 Paint War Game 是使用 HTML、CSS 和 JavaScript 开发的。谈到游戏玩法,这款游戏的主要目标是建造比敌人更多的油漆砖。您所要做的就是使用 WASD 键输入玩家的动作。您可以使用 VS Code 来运行该项目。 关于项目 每次您的玩家走过一块瓷砖时,它都会被涂成您的团队颜色。您必须在同一块瓷砖上走 4 次才能获得更多游戏点数。瓷砖会被您的团队挡住,并且不能再被偷走。如果您走过另一支球队的瓷砖,它会像您第一次走过时一样被涂上颜色。如果您创建一个封闭的被阻挡瓷砖图形,图形内所有未被阻挡的瓷砖都将固定为您的团队颜色。这个游戏充满乐趣,创造和重新即兴发挥会更有趣。 要运行此项目,我们建议您使用现代浏览器,例如 Google Chrome、  Mozilla Firefox。该游戏可能还支持 Explorer/Microsoft Edge。 演示: 该项目为国外大神项目,可以作为毕业设计的项目,也可以作为大作业项目,不用担心代码重复,设计重复等,如果需要对项目进行修改,需要具备一定基础知识。 注意:如果装有360等杀毒软件,可能会出现误报的情况,源码本身并无病毒,使用源码时可以关闭360,或者添加信任。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值