基本类型

布尔型

  1. var b bool
  2. b = true
  3. fmt.Printf("b is of type %t\n", b)
  4. e := bool(true)
  5. fmt.Printf("e is of type %t\n", e)
  • 长度:1字节
  • 取值范围:true/false
  • 只能使用true/false值,不能使用数字代替布尔值

整形 int/uint

  1. package main
  2. import "fmt"
  3. func main() {
  4. // n 是一个长度为 10 的数组
  5. var n [10]int
  6. var i,j int
  7. /* 为数组 n 初始化元素 */
  8. for i = 0; i < 10; i++ {
  9. n[i] = i + 100 /* 设置元素为 i + 100 */
  10. }
  11. /* 输出每个数组元素的值 */
  12. for j = 0; j < 10; j++ {
  13. fmt.Printf("Element[%d] = %d\n", j, n[j] )
  14. }
  15. }
  • int/uint
  • 根据平台可能为32/64位

8位整型 int8/uint8

  1. u8 := []uint8{98, 99}
  2. a := byte(255) //11111111 这是byte的极限, 因为 a := byte(256)//越界报错, 0~255正好256个数,不能再高了
  3. b := uint8(255) //11111111 这是uint8的极限,因为 c := uint8(256)//越界报错,0~255正好256个数,不能再高了
  4. c := int8(127) //01111111 这是int8的极限, 因为 b := int8(128)//越界报错, 0~127正好128个数,所以int8的极限只是256的一半
  5. d := int8(a) //11111111 打印出来则是-0000001,int8(128)、int8(255)、int8(byte(255))都报错越界,因为int极限是127,但是却可以写:int8(a),第一位拿来当符号了
  6. e := int8(c) //01111111 打印出来还是01111111
  7. fmt.Printf("%08b %d \n", a, a)
  8. fmt.Printf("%08b %d \n", b, b)
  9. fmt.Printf("%08b %d \n", c, c)
  10. fmt.Printf("%08b %d \n", d, d)
  11. fmt.Printf("%08b %d \n", e, e)
  • int8/uint8
  • 长度:1字节
  • 取值范围:-128127/0255

字节型 byte

  1. // 这里不能写成 b := []byte{"Golang"},这里是利用类型转换。
  2. b := []byte("Golang")
  3. c := []byte("go")
  4. d := []byte("Go")
  5. println(b,c,d)
  • byte(uint8别名)

基本处理函数

  • Contains() 返回是否包含子切片
  • Count() 子切片非重叠实例的数量
  • Map() 函数,将byte 转化为Unicode,然后进行替换
  • Repeat() 将切片复制count此,返回这个新的切片
  • Replace() 将切片中的一部分 替换为另外的一部分
  • Runes() 将 S 转化为对应的 UTF-8 编码的字节序列,并且返回对应的Unicode 切片
  • Join() 函数,将子字节切片连接到一起。

可以参考下面列子来理解上面7个方法,例子 byte.go

  1. package main
  2. import (
  3. "bytes"
  4. "fmt"
  5. )
  6. func main() {
  7. // 这里不能写成 b := []byte{"Golang"},这里是利用类型转换。
  8. b := []byte("Golang")
  9. subslice1 := []byte("go")
  10. subslice2 := []byte("Go")
  11. // func Contains(b, subslice [] byte) bool
  12. // 检查字节切片b ,是否包含子字节切片 subslice
  13. fmt.Println(bytes.Contains(b, subslice1))
  14. fmt.Println(bytes.Contains(b, subslice2))
  15. s2 := []byte("同学们,上午好")
  16. m := func(r rune) rune {
  17. if r == '上' {
  18. r = '下'
  19. }
  20. return r
  21. }
  22. fmt.Println(string(s2))
  23. // func Map(mapping func(r rune) rune, s []byte) []byte
  24. // Map函数: 首先将 s 转化为 UTF-8编码的字符序列,
  25. // 然后使用 mapping 将每个Unicode字符映射为对应的字符,
  26. // 最后将结果保存在一个新的字节切片中。
  27. fmt.Println(string(bytes.Map(m, s2)))
  28. s3 := []byte("google")
  29. old := []byte("o")
  30. //这里 new 是一个字节切片,不是关键字了
  31. new := []byte("oo")
  32. n := 1
  33. // func Replace(s, old, new []byte, n int) []byte
  34. //返回字节切片 S 的一个副本, 并且将前n个不重叠的子切片 old 替换为 new,如果n < 0 那么不限制替换的数量
  35. fmt.Println(string(bytes.Replace(s3, old, new, n)))
  36. fmt.Println(string(bytes.Replace(s3, old, new, -1)))
  37. // 将字节切片 转化为对应的 UTF-8编码的字节序列,并且返回对应的 Unicode 切片。
  38. s4 := []byte("中华人民共和国")
  39. r1 := bytes.Runes(s4)
  40. // func Runes(b []byte) []rune
  41. fmt.Println(string(s4), len(s4)) // 字节切片的长度
  42. fmt.Println(string(r1), len(r1)) // rune 切片的长度
  43. // 字节切片 的每个元素,依旧是字节切片。
  44. s5 := [][]byte{
  45. []byte("你好"),
  46. []byte("世界"), //这里的逗号,必不可少
  47. }
  48. sep := []byte(",")
  49. // func Join(s [][]byte, sep []byte) []byte
  50. // 用字节切片 sep 吧 s中的每个字节切片连接成一个,并且返回.
  51. fmt.Println(string(bytes.Join(s5, sep)))
  52. }

16位整型 int16/uint16

  • int16/uint16
  • 长度:2字节
  • 取值范围:-3276832767/065535

32位整型 int32(别名rune)/uint32

  • int32(别名rune)/uint32
  • 长度:4字节
  • 取值范围:-2^32/22^32/2-1/02^32-1

64位整型 int64/uint64

  • int64/uint64
  • 长度:8字节
  • 取值范围:-2^64/22^64/2-1/02^64-1

浮点型 float32/float64

  1. package main
  2. import "fmt"
  3. func main() {
  4. var x float64
  5. x = 20.0
  6. fmt.Println(x)
  7. fmt.Printf("x is of type %T\n", x)
  8. a := float64(20.0)
  9. b := 42
  10. fmt.Println(a)
  11. fmt.Println(b)
  12. fmt.Printf("a is of type %T\n", a)
  13. fmt.Printf("b is of type %T\n", b)
  14. }

实例:float.go

  • float32/float64
  • 长度:4/8字节
  • 小数位:精确到 7/15 位小数

复数 complex64/complex128

  • complex64/complex128
  • 长度:8/16

指针整数型 uintptr

用于指针运算,GC 不把 uintptr 当指针,uintptr 无法持有对象。uintptr 类型的目标会被回收。

  • uintptr
  • 保存指正的 32 位或者 64 位整数型
  1. // 示例:通过指针修改结构体字段
  2. package main
  3. import (
  4. "fmt"
  5. "unsafe"
  6. )
  7. func main() {
  8. s := struct {
  9. a byte
  10. b byte
  11. c byte
  12. d int64
  13. }{0, 0, 0, 0}
  14. // 将结构体指针转换为通用指针
  15. p := unsafe.Pointer(&s)
  16. // 保存结构体的地址备用(偏移量为 0)
  17. up0 := uintptr(p)
  18. // 将通用指针转换为 byte 型指针
  19. pb := (*byte)(p)
  20. // 给转换后的指针赋值
  21. *pb = 10
  22. // 结构体内容跟着改变
  23. fmt.Println(s)
  24. // 偏移到第 2 个字段
  25. up := up0 + unsafe.Offsetof(s.b)
  26. // 将偏移后的地址转换为通用指针
  27. p = unsafe.Pointer(up)
  28. // 将通用指针转换为 byte 型指针
  29. pb = (*byte)(p)
  30. // 给转换后的指针赋值
  31. *pb = 20
  32. // 结构体内容跟着改变
  33. fmt.Println(s)
  34. // 偏移到第 3 个字段
  35. up = up0 + unsafe.Offsetof(s.c)
  36. // 将偏移后的地址转换为通用指针
  37. p = unsafe.Pointer(up)
  38. // 将通用指针转换为 byte 型指针
  39. pb = (*byte)(p)
  40. // 给转换后的指针赋值
  41. *pb = 30
  42. // 结构体内容跟着改变
  43. fmt.Println(s)
  44. // 偏移到第 4 个字段
  45. up = up0 + unsafe.Offsetof(s.d)
  46. // 将偏移后的地址转换为通用指针
  47. p = unsafe.Pointer(up)
  48. // 将通用指针转换为 int64 型指针
  49. pi := (*int64)(p)
  50. // 给转换后的指针赋值
  51. *pi = 40
  52. // 结构体内容跟着改变
  53. fmt.Println(s)
  54. }

数组类型 array

数组声明语法

  1. var variable_name [SIZE]variable_type

数组是具有相同唯一类型的一组已编号且长度固定的数据项序列,这种类型可以是任意的原始类型例如整形、字符串或者自定义类型。下面是一个简单的对数组操作的例子array.go

  1. package main
  2. import "fmt"
  3. func main() {
  4. // 声明一个长度为5的整数数组
  5. // 一旦数组被声明了,那么它的数据类型跟长度都不能再被改变。
  6. var array1 [5]int
  7. fmt.Printf("array1: %d\n\n", array1)
  8. // 声明一个长度为5的整数数组
  9. // 初始化每个元素
  10. array2 := [5]int{12, 123, 1234, 12345, 123456}
  11. array2[1] = 5000
  12. fmt.Printf("array2: %d\n\n", array2[1])
  13. // n 是一个长度为 10 的数组
  14. var n [10]int
  15. var i,j int
  16. /* 为数组 n 初始化元素 */
  17. for i = 0; i < 10; i++ {
  18. n[i] = i + 100 /* 设置元素为 i + 100 */
  19. }
  20. /* 输出每个数组元素的值 */
  21. for j = 0; j < 10; j++ {
  22. fmt.Printf("Element[%d] = %d\n", j, n[j] )
  23. }
  24. /* 数组 - 5 行 2 列*/
  25. var a = [5][2]int{ {0,0}, {1,2}, {2,4}, {3,6},{4,8}}
  26. var e, f int
  27. /* 输出数组元素 */
  28. for e = 0; e < 5; e++ {
  29. for f = 0; f < 2; f++ {
  30. fmt.Printf("a[%d][%d] = %d\n", e,f, a[e][f] )
  31. }
  32. }
  33. }

初始化数组中 {} 中的元素个数不能大于 [] 中的数字。如果忽略 [] 中的数字不设置数组大小,Go 语言会根据元素的个数来设置数组的大小:

  1. var array1 = [...]float32{1000.0, 2.0, 3.4, 7.0, 50.0}

数组元素可以通过索引(位置)来读取。格式为数组名后加中括号,中括号中为索引的值。例如:

  1. float32 salary = array1[9]

以上实例读取了数组array110个元素的值。

多维数组,下面例子

  1. // 三行四列
  2. a = [3][4]int{
  3. {0, 1, 2, 3} , /* 第一行索引为 0 */
  4. {4, 5, 6, 7} , /* 第二行索引为 1 */
  5. {8, 9, 10, 11} /* 第三行索引为 2 */
  6. }

访问多维数组

  1. // 访问第2行第3列
  2. int val = a[2][3]

结构类型 struct

  1. package main
  2. import "fmt"
  3. type Vertex struct {
  4. X int
  5. Y int
  6. }
  7. func main() {
  8. fmt.Println(Vertex{1, 2})
  9. // 结构体字段使用点号来访问。
  10. v := Vertex{1, 2}
  11. v.X = 4
  12. fmt.Println(v.X)
  13. // 结构体字段可以通过结构体指针来访问。
  14. e := Vertex{1, 2}
  15. p := &e
  16. p.X = 1e9
  17. fmt.Println(e)
  18. var (
  19. v1 = Vertex{1, 2} // 类型为 Vertex
  20. v2 = Vertex{X: 1} // Y:0 被省略
  21. v3 = Vertex{} // X:0 和 Y:0
  22. p = &Vertex{1, 2} // 类型为 *Vertex , 特殊的前缀 & 返回一个指向结构体的指针
  23. )
  24. fmt.Println(v1, p, v2, v3)
  25. }

简单的结构体

  1. type T struct {a, b int}

结构体里的字段都有 名字,像 field1field2 等,如果字段在代码中从来也不会被用到,那么可以命名它为 _。上面简单的结构体定义,下面调用方法:

  1. var s T
  2. s.a = 5
  3. s.b = 8

数组可以看作是一种结构体类型,不过它使用下标而不是具名的字段。

  1. var t *T
  2. t = new(T)

上面简单的管用语句方法t := new(T),变量 t 是一个指向 T 的指针,此时结构体字段的值是它们所属类型的零值。

声明 var t T 也会给 t 分配内存,并零值化内存,但是这个时候 t 是类型T。在这两种方式中,t 通常被称做类型 T 的一个实例(instance)或对象(object)。

一个非常简单的例子structs_fields.go运行例子查看结果:

  1. go run test/structs_fields.go
  2. The int is: 10
  3. The float is: 15.500000
  4. The string is: Chris
  5. &{10 15.5 Chris}

使用 new

字符串类型 string

  1. var str string //声明一个字符串
  2. str = "Go lang" //赋值
  3. ch :=str[0] //获取第一个字符
  4. len :=len(str) //字符串的长度,len是内置函数 ,len=5

len函数是Go中内置函数,不引入strings包即可使用。len(string)返回的是字符串的字节数。len函数所支持的入参类型如下:

  • len(Array) 数组的元素个数
  • len(*Array) 数组指针中的元素个数,如果入参为nil则返回0
  • len(Slice) 数组切片中元素个数,如果入参为nil则返回0
  • len(map) 字典中元素个数,如果入参为nil则返回0
  • len(Channel) Channel buffer队列中元素个数

接口类型 inteface

  1. package main
  2. import (
  3. "fmt"
  4. "math"
  5. )
  6. /* 定义一个 interface */
  7. type shape interface {
  8. area() float64
  9. }
  10. /* 定义一个 circle */
  11. type circle struct {
  12. x,y,radius float64
  13. }
  14. /* 定义一个 rectangle */
  15. type rectangle struct {
  16. width, height float64
  17. }
  18. /* 定义一个circle方法 (实现 shape.area())*/
  19. func(circle circle) area() float64 {
  20. return math.Pi * circle.radius * circle.radius
  21. }
  22. /* 定义一个rectangle方法 (实现 shape.area())*/
  23. func(rect rectangle) area() float64 {
  24. return rect.width * rect.height
  25. }
  26. /* 定义一个shape的方法*/
  27. func getArea(shape shape) float64 {
  28. return shape.area()
  29. }
  30. func main() {
  31. circle := circle{x:0,y:0,radius:5}
  32. rectangle := rectangle {width:10, height:5}
  33. fmt.Printf("circle area: %f\n",getArea(circle))
  34. fmt.Printf("rectangle area: %f\n",getArea(rectangle))
  35. }

实例:inteface.go

函数类型 func

  1. package main
  2. import "fmt"
  3. type functinTyoe func(int, int) // 声明了一个函数类型
  4. func (f functinTyoe)Serve() {
  5. fmt.Println("serve2")
  6. }
  7. func serve(int,int) {
  8. fmt.Println("serve1")
  9. }
  10. func main() {
  11. a := functinTyoe(serve)
  12. a(1,2)
  13. a.Serve()
  14. }

实例:func.go

引用类型 func

切片

是一种可以动态数组,可以按我们的希望增长和收缩。

  • slice

Map

是一种无序的键值对的集合。是一种集合,所以我们可以像迭代数组和 slice 那样迭代它。

  • map
  1. // 通过 make 来创建
  2. dict := make(map[string]int)
  3. // 通过字面值创建
  4. dict := map[string]string{"Red": "#da1337", "Orange": "#e95a22"}
  5. // 给 map 赋值就是指定合法类型的键,然后把值赋给键
  6. colors := map[string]string{}
  7. colors["Red"] = "#da1337"
  8. // 不初始化 map , 就会创建一个 nil map。nil map 不能用来存放键值对,否则会报运行时错误
  9. var colors map[string]string
  10. colors["Red"] = "#da1337"
  11. // Runtime Error:
  12. // panic: runtime error: assignment to entry in nil map
  13. //选择是只返回值,然后判断是否是零值来确定键是否存在。
  14. value := colors["Blue"]
  15. if value != "" {
  16. fmt.Println(value)
  17. }

在函数间传递 map 不是传递 map 的拷贝。所以如果我们在函数中改变了 map,那么所有引用 map 的地方都会改变

  1. func main() {
  2. colors := map[string]string{
  3. "AliceBlue": "#f0f8ff",
  4. "Coral": "#ff7F50",
  5. "DarkGray": "#a9a9a9",
  6. "ForestGreen": "#228b22",
  7. }
  8. for key, value := range colors {
  9. fmt.Printf("Key: %s Value: %s\n", key, value)
  10. }
  11. removeColor(colors, "Coral")
  12. for key, value := range colors {
  13. fmt.Printf("Key: %s Value: %s\n", key, value)
  14. }
  15. }
  16. func removeColor(colors map[string]string, key string) {
  17. delete(colors, key)
  18. }

通道

  • chan

类型别名

  1. type (
  2. byte int8
  3. rune init32
  4. 文本 string
  5. )
  6. var b 文本
  7. b = "别名类型,可以是中文!"