基本类型

布尔型

  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字节
  • 取值范围:-128~127/0~255字节型 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字节
  • 取值范围:-32768~32767/0~6553532位整型 int32(别名rune)/uint32

  • int32(别名rune)/uint32

  • 长度:4字节
  • 取值范围:-2^32/2~2^32/2-1/0~2^32-164位整型 int64/uint64

  • int64/uint64

  • 长度:8字节
  • 取值范围:-2^64/2~2^64/2-1/0~2^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

切片

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

  • sliceMap

是一种无序的键值对的集合。是一种集合,所以我们可以像迭代数组和 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 = "别名类型,可以是中文!"

常量变量

常量 const

  1. package main
  2. import "unsafe"
  3. // 常量可以用len(), cap(), unsafe.Sizeof()常量计算表达式的值。
  4. // 常量表达式中,函数必须是内置函数,否则编译不过:
  5. const (
  6. a = "abc"
  7. b = len(a)
  8. c = unsafe.Sizeof(a)
  9. )
  10. func main(){
  11. const (
  12. PI = 3.14
  13. const1 = "1"
  14. )
  15. const LENGTH int = 10
  16. const e, f, g = 1, false, "str" //多重赋值
  17. println(a, b, c,PI, LENGTH)
  18. }

上面例子const.go

iota 特殊常量,可以认为是一个可以被编译器修改的常量。iota.go

  1. package main
  2. import "fmt"
  3. func main() {
  4. const (
  5. // 第一个 iota 等于 0,每当 iota 在新的一行被使用时,它的值都会自动加 1;
  6. // 所以 a=0, b=1, c=2 可以简写为如下形式:
  7. a = iota //0
  8. b //1
  9. c //2
  10. d = "ha" //独立值,iota += 1
  11. e //"ha" iota += 1
  12. f = 100 //iota +=1
  13. g //100 iota +=1
  14. h = iota //7,恢复计数
  15. i //8
  16. )
  17. fmt.Println(a,b,c,d,e,f,g,h,i)
  18. }

变量 var

  1. var (
  2. name = "gopher"
  3. name1 = "1"
  4. )
  5. // 变量声明
  6. var a int
  7. a = 11 /* 赋值 */
  8. // 变量声明 并赋值
  9. var b int = 12
  10. // 应用在函数体内的方式
  11. var a, b, c, d int = 1, 2, 3, 4
  12. // a =1
  13. // b =2
  14. // c =3
  15. // d =4
  16. var a, _, c, d int = 1, 2, 3, 4
  17. // 忽略 _ 返回值忽略
  • 全局变量名 以大写开头
  • 全局变量不可以省略 var ,可以使用并行的方式
  • 所有变量都可以使用类型推断
  • 局部变量不可以使用var()简写的形式变量的类型转换
  1. // 只能类型显式转换
  2. var a float32 = 1.1
  3. // 省略var, 简短形式,使用 := 赋值操作符
  4. b := int(a)
  5. // 不兼容的类型不能转换类型

多变量声明

  1. var x, y int
  2. // 这种因式分解关键字的写法一般用于声明全局变量
  3. var (
  4. a int
  5. b bool
  6. )
  7. var c, d int = 1, 2
  8. var e, f = 123, "hello"
  9. //这种不带声明格式的只能在函数体中出现
  10. //g, h := 123, "hello"

语言运算符

算术运算符

  1. package main
  2. import "fmt"
  3. func main() {
  4. var a int = 21
  5. var b int = 10
  6. var c int
  7. c = a + b
  8. fmt.Printf("第一行 - c 的值为 %d\n", c ) // 第一行 - c 的值为 31
  9. c = a - b
  10. fmt.Printf("第二行 - c 的值为 %d\n", c ) // 第二行 - c 的值为 11
  11. c = a * b
  12. fmt.Printf("第三行 - c 的值为 %d\n", c ) // 第三行 - c 的值为 210
  13. c = a / b
  14. fmt.Printf("第四行 - c 的值为 %d\n", c ) // 第四行 - c 的值为 2
  15. c = a % b
  16. fmt.Printf("第五行 - c 的值为 %d\n", c ) // 第五行 - c 的值为 1
  17. a++
  18. fmt.Printf("第六行 - c 的值为 %d\n", a ) // 第六行 - c 的值为 22
  19. a--
  20. fmt.Printf("第七行 - c 的值为 %d\n", a ) // 第七行 - c 的值为 21
  21. }

下表列出了所有Go语言的算术运算符。假定 A 值为 10,B 值为 20。

运算符描述实例
+相加A + B 输出结果 30
-相减A - B 输出结果 -10
相乘A B 输出结果 200
/相除B / A 输出结果 2
%求余B % A 输出结果 0
++自增A++ 输出结果 11
自减A— 输出结果 9

关系运算符

  1. package main
  2. import "fmt"
  3. func main() {
  4. var a int = 21
  5. var b int = 10
  6. if( a == b ) {
  7. fmt.Printf("第一行 - a 等于 b\n" )
  8. } else {
  9. fmt.Printf("第一行 - a 不等于 b\n" )
  10. }
  11. if ( a < b ) {
  12. fmt.Printf("第二行 - a 小于 b\n" )
  13. } else {
  14. fmt.Printf("第二行 - a 不小于 b\n" )
  15. }
  16. if ( a > b ) {
  17. fmt.Printf("第三行 - a 大于 b\n" )
  18. } else {
  19. fmt.Printf("第三行 - a 不大于 b\n" )
  20. }
  21. /* 让我们改变a和b的值 */
  22. a = 5
  23. b = 20
  24. if ( a <= b ) {
  25. fmt.Printf("第四行 - a 小于等于 b\n" )
  26. }
  27. if ( b >= a ) {
  28. fmt.Printf("第五行 - b 大于等于 a\n" )
  29. }
  30. }

下表列出了所有Go语言的关系运算符。假定 A 值为 10,B 值为 20。

运算符描述实例
==检查两个值是否相等,如果相等返回 True 否则返回 False。(A == B) 为 False
!=检查两个值是否不相等,如果不相等返回 True 否则返回 False。(A != B) 为 True
>检查左边值是否大于右边值,如果是返回 True 否则返回 False。(A > B) 为 False
<检查左边值是否小于右边值,如果是返回 True 否则返回 False。(A < B) 为 True
>=检查左边值是否大于等于右边值,如果是返回 True 否则返回 False。(A >= B) 为 False
<=检查左边值是否小于等于右边值,如果是返回 True 否则返回 False。A <= B) 为 True

逻辑运算符

  1. package main
  2. import "fmt"
  3. func main() {
  4. var a bool = true
  5. var b bool = false
  6. if ( a && b ) {
  7. fmt.Printf("第一行 - 条件为 true\n" )
  8. }
  9. if ( a || b ) {
  10. fmt.Printf("第二行 - 条件为 true\n" )
  11. }
  12. /* 修改 a 和 b 的值 */
  13. a = false
  14. b = true
  15. if ( a && b ) {
  16. fmt.Printf("第三行 - 条件为 true\n" )
  17. } else {
  18. fmt.Printf("第三行 - 条件为 false\n" )
  19. }
  20. if ( !(a && b) ) {
  21. fmt.Printf("第四行 - 条件为 true\n" )
  22. }
  23. }

下表列出了所有Go语言的逻辑运算符。假定 A 值为 True,B 值为 False d。

运算符描述实例
&&逻辑 AND 运算符。 如果两边的操作数都是 True,则条件 True,否则为 False。(A && B) 为 False
\\逻辑 OR 运算符。 如果两边的操作数有一个 True,则条件 True,否则为 False。(AB) 为 True
!逻辑 NOT 运算符。 如果条件为 True,则逻辑 NOT 条件 False,否则为 True。!(A && B) 为 True

位运算符

  1. package main
  2. import "fmt"
  3. func main() {
  4. var a uint = 60 /* 60 = 0011 1100 */
  5. var b uint = 13 /* 13 = 0000 1101 */
  6. var c uint = 0
  7. c = a & b /* 12 = 0000 1100 */
  8. fmt.Printf("第一行 - c 的值为 %d\n", c ) // 第一行 - c 的值为 12
  9. c = a | b /* 61 = 0011 1101 */
  10. fmt.Printf("第二行 - c 的值为 %d\n", c ) // 第二行 - c 的值为 61
  11. c = a ^ b /* 49 = 0011 0001 */
  12. fmt.Printf("第三行 - c 的值为 %d\n", c ) // 第三行 - c 的值为 49
  13. c = a << 2 /* 240 = 1111 0000 */
  14. fmt.Printf("第四行 - c 的值为 %d\n", c ) // 第四行 - c 的值为 240
  15. c = a >> 2 /* 15 = 0000 1111 */
  16. fmt.Printf("第五行 - c 的值为 %d\n", c ) // 第五行 - c 的值为 15
  17. }

Go 语言支持的位运算符如下表所示。假定 A 为60,B 为13:

运算符描述实例
&按位与运算符”&”是双目运算符。 其功能是参与运算的两数各对应的二进位相与。(A & B) 结果为 12, 二进制为 0000 1100
\按位或运算符 \是双目运算符。 其功能是参与运算的两数各对应的二进位相或。(A \B) 结果为 61, 二进制为 0011 1101
^按位异或运算符”^”是双目运算符。 其功能是参与运算的两数各对应的二进位相异或,当两对应的二进位相异时,结果为1。(A ^ B) 结果为 49, 二进制为 0011 0001
<<左移运算符”<<”是双目运算符。左移n位就是乘以2的n次方。 其功能把”<<”左边的运算数的各二进位全部左移若干位,由”<<”右边的数指定移动的位数,高位丢弃,低位补0。A << 2 结果为 240 ,二进制为 1111 0000
>>右移运算符”>>”是双目运算符。右移n位就是除以2的n次方。 其功能是把”>>”左边的运算数的各二进位全部右移若干位,”>>”右边的数指定移动的位数。A >> 2 结果为 15 ,二进制为 0000 1111

赋值运算符

  1. package main
  2. import "fmt"
  3. func main() {
  4. var a int = 21
  5. var c int
  6. c = a
  7. fmt.Printf("第 1 行 - = 运算符实例,c 值为 = %d\n", c )
  8. // 第 1 行 - = 运算符实例,c 值为 = 21
  9. c += a
  10. fmt.Printf("第 2 行 - += 运算符实例,c 值为 = %d\n", c )
  11. // 第 2 行 - += 运算符实例,c 值为 = 42
  12. c -= a
  13. fmt.Printf("第 3 行 - -= 运算符实例,c 值为 = %d\n", c )
  14. // 第 3 行 - -= 运算符实例,c 值为 = 21
  15. c *= a
  16. fmt.Printf("第 4 行 - *= 运算符实例,c 值为 = %d\n", c )
  17. // 第 4 行 - *= 运算符实例,c 值为 = 441
  18. c /= a
  19. fmt.Printf("第 5 行 - /= 运算符实例,c 值为 = %d\n", c )
  20. // 第 5 行 - /= 运算符实例,c 值为 = 21
  21. c = 200;
  22. c <<= 2
  23. fmt.Printf("第 6 行 - <<= 运算符实例,c 值为 = %d\n", c )
  24. // 第 6 行 - <<= 运算符实例,c 值为 = 800
  25. c >>= 2
  26. fmt.Printf("第 7 行 - >>= 运算符实例,c 值为 = %d\n", c )
  27. // 第 7 行 - >>= 运算符实例,c 值为 = 200
  28. c &= 2
  29. fmt.Printf("第 8 行 - &= 运算符实例,c 值为 = %d\n", c )
  30. // 第 8 行 - &= 运算符实例,c 值为 = 0
  31. c ^= 2
  32. fmt.Printf("第 9 行 - ^= 运算符实例,c 值为 = %d\n", c )
  33. // 第 9 行 - ^= 运算符实例,c 值为 = 2
  34. c |= 2
  35. fmt.Printf("第 10 行 - |= 运算符实例,c 值为 = %d\n", c )
  36. // 第 10 行 - |= 运算符实例,c 值为 = 2
  37. }
运算符描述实例
=简单的赋值运算符,将一个表达式的值赋给一个左值sC = A + B 将 A + B 表达式结果赋值给 C
+=相加后再赋值sC += A 等于 C = C + A
-=相减后再赋值sC -= A 等于 C = C - A
*=相乘后再赋值sC = A 等于 C = C A
/=相除后再赋值sC /= A 等于 C = C / A
%=求余后再赋值sC %= A 等于 C = C % A
<<=左移后赋值sC <<= 2 等于 C = C << 2
>>=右移后赋值sC >>= 2 等于 C = C >> 2
&=按位与后赋值sC &= 2 等于 C = C & 2
^=按位异或后赋值sC ^= 2 等于 C = C ^ 2
\=按位或后赋值sC \= 2 等于 C = C \2

其他运算符

  1. package main
  2. import "fmt"
  3. func main() {
  4. var a int = 4
  5. var b int32
  6. var c float32
  7. var ptr *int
  8. /* 运算符实例 */
  9. fmt.Printf("第 1 行 - a 变量类型为 = %T\n", a ); // 第 1 行 - a 变量类型为 = int
  10. fmt.Printf("第 2 行 - b 变量类型为 = %T\n", b ); // 第 2 行 - b 变量类型为 = int32
  11. fmt.Printf("第 3 行 - c 变量类型为 = %T\n", c ); // 第 3 行 - c 变量类型为 = float32
  12. /* & 和 * 运算符实例 */
  13. ptr = &a /* 'ptr' 包含了 'a' 变量的地址 */
  14. fmt.Printf("a 的值为 %d\n", a); // a 的值为 4
  15. fmt.Printf("*ptr 为 %d\n", *ptr); // *ptr 为 4
  16. }
运算符描述实例
&返回变量存储地址&a; 将给出变量的实际地址。
指针变量。a; 是一个指针变量

运算符优先级

  1. package main
  2. import "fmt"
  3. func main() {
  4. var a int = 20
  5. var b int = 10
  6. var c int = 15
  7. var d int = 5
  8. var e int;
  9. // 通过使用括号来临时提升某个表达式的整体运算优先级。
  10. e = (a + b) * c / d; // ( 30 * 15 ) / 5
  11. fmt.Printf("(a + b) * c / d 的值为 : %d\n", e );
  12. e = ((a + b) * c) / d; // (30 * 15 ) / 5
  13. fmt.Printf("((a + b) * c) / d 的值为 : %d\n" , e );
  14. e = (a + b) * (c / d); // (30) * (15/5)
  15. fmt.Printf("(a + b) * (c / d) 的值为 : %d\n", e );
  16. e = a + (b * c) / d; // 20 + (150/5)
  17. fmt.Printf("a + (b * c) / d 的值为 : %d\n" , e );
  18. }

有些运算符拥有较高的优先级,二元运算符的运算方向均是从左至右。下表列出了所有运算符以及它们的优先级,由上至下代表优先级由高到低:

优先级运算符
7^ !
6* / % << >> & &^
5+ - \^
4== != < <= >= >
3<-
2&&
1\\

流程控制语句

for 循环语句

  1. package main
  2. import "fmt"
  3. func main() {
  4. sum := 0
  5. // 如果条件表达式的值变为 false,那么迭代将终止。
  6. for i := 0; i < 10; i++ {
  7. sum += i
  8. }
  9. fmt.Println(sum)
  10. // 循环初始化语句和后置语句都是可选的。
  11. // for 是 Go 的 “while”
  12. // 基于此可以省略分号:C 的 while 在 Go 中叫做 for 。
  13. // 如果省略了循环条件,循环就不会结束,因此可以用更简洁地形式表达死循环。
  14. sum2 := 1
  15. for ; sum2 < 1000; {
  16. sum2 += sum2
  17. }
  18. fmt.Println(sum2)
  19. }

基本的 for 循环包含三个由分号分开的组成部分:

  • 初始化语句:在第一次循环执行前被执行
  • 循环条件表达式:每轮迭代开始前被求值
  • 后置语句:每轮迭代后被执行if 语句
  1. package main
  2. import (
  3. "fmt"
  4. "math"
  5. )
  6. func sqrt(x float64) string {
  7. if x < 0 {
  8. return sqrt(-x) + "i"
  9. }
  10. return fmt.Sprint(math.Sqrt(x))
  11. }
  12. func main() {
  13. fmt.Println(sqrt(2), sqrt(-4))
  14. }

就像 for 循环一样,Go 的 if 语句也不要求用 ( ) 将条件括起来,同时, { } 还是必须有的。

if 的便捷语句

  1. package main
  2. import (
  3. "fmt"
  4. "math"
  5. )
  6. func pow(x, n, lim float64) float64 {
  7. if v := math.Pow(x, n); v < lim {
  8. return v
  9. }
  10. return lim
  11. }
  12. func main() {
  13. fmt.Println(
  14. pow(3, 2, 10),
  15. pow(3, 3, 20),
  16. )
  17. }

if 和 else 语句

  1. package main
  2. import (
  3. "fmt"
  4. "math"
  5. )
  6. func pow(x, n, lim float64) float64 {
  7. if v := math.Pow(x, n); v < lim {
  8. return v
  9. } else {
  10. fmt.Printf("%g >= %g\n", v, lim)
  11. }
  12. // 这里开始就不能使用 v 了
  13. return lim
  14. }
  15. func main() {
  16. // 两个 pow 调用都在 main 调用 fmt.Println 前执行完毕了。
  17. fmt.Println(
  18. pow(3, 2, 10),
  19. pow(3, 3, 20),
  20. )
  21. }

在 if 的便捷语句定义的变量同样可以在任何对应的 else 块中使用。

switch 语句

  1. package main
  2. import (
  3. "fmt"
  4. "runtime"
  5. )
  6. func main() {
  7. fmt.Print("Go runs on ")
  8. switch os := runtime.GOOS; os {
  9. case "darwin":
  10. fmt.Println("OS X.")
  11. case "linux":
  12. fmt.Println("Linux.")
  13. default:
  14. // freebsd, openbsd,
  15. // plan9, windows...
  16. fmt.Printf("%s.", os)
  17. }
  18. }

在 if 的便捷语句定义的变量同样可以在任何对应的 else 块中使用。

switch 的执行顺序: 条件从上到下的执行,当匹配成功的时候停止。

  1. package main
  2. import (
  3. "fmt"
  4. "time"
  5. )
  6. func main() {
  7. fmt.Println("When's Saturday?")
  8. today := time.Now().Weekday()
  9. switch time.Saturday {
  10. case today + 0:
  11. fmt.Println("Today.")
  12. case today + 1:
  13. fmt.Println("Tomorrow.")
  14. case today + 2:
  15. fmt.Println("In two days.")
  16. default:
  17. fmt.Println("Too far away.")
  18. }
  19. }

没有条件的 switch 同 switch true 一样。

  1. package main
  2. import (
  3. "fmt"
  4. "time"
  5. )
  6. func main() {
  7. t := time.Now()
  8. switch {
  9. case t.Hour() < 12:
  10. fmt.Println("Good morning!")
  11. case t.Hour() < 17:
  12. fmt.Println("Good afternoon.")
  13. default:
  14. fmt.Println("Good evening.")
  15. }
  16. }

defer 语句

  1. package main
  2. import "fmt"
  3. func main() {
  4. // 2. 在输出 world
  5. defer fmt.Println("world")
  6. // 1. 先输出 hello
  7. fmt.Println("hello")
  8. }

defer 语句会延迟函数的执行直到上层函数返回。延迟调用的参数会立刻生成,但是在上层函数返回前函数都不会被调用。

defer 栈

延迟的函数调用被压入一个栈中。当函数返回时, 会按照后进先出的顺序调用被延迟的函数调用。

  1. package main
  2. import "fmt"
  3. func main() {
  4. fmt.Println("counting")
  5. for i := 0; i < 10; i++ {
  6. defer fmt.Println(i)
  7. }
  8. fmt.Println("done")
  9. }

可以运行demo defer 查看效果。

结构体

结构体字段

结构体字段使用点号来访问。

  1. package main
  2. import "fmt"
  3. type Vertex struct {
  4. X int
  5. Y int
  6. }
  7. func main() {
  8. v := Vertex{1, 2}
  9. v.X = 4
  10. fmt.Println(v.X)
  11. }

结构体指针

结构体字段使用点号来访问。

  1. package main
  2. import "fmt"
  3. type Vertex struct {
  4. X int
  5. Y int
  6. }
  7. func main() {
  8. v := Vertex{1, 2}
  9. p := &v
  10. p.X = 1e9
  11. fmt.Println(v)
  12. }

结构体文法

结构体文法表示通过结构体字段的值作为列表来新分配一个结构体。使用 Name: 语法可以仅列出部分字段。(字段名的顺序无关。)特殊的前缀 & 返回一个指向结构体的指针。

  1. package main
  2. import "fmt"
  3. type Vertex struct {
  4. X int
  5. Y int
  6. }
  7. func main() {
  8. v := Vertex{1, 2}
  9. p := &v
  10. p.X = 1e9
  11. fmt.Println(v)
  12. }

资源导航

官方

文章资源来源与Go社区的