[ Go语言基础 | 青训营课程笔记 ]01

65 阅读7分钟

[ Go语言基础 | 青训营课程笔记 ]

这是我参与「第五届青训营」伴学笔记创作活动的第 1 天

一.简介

1.Go语言特点

  1. 高性能、高并发
  2. 语法简单、学习曲线平缓
  3. 丰富的标准库
  4. 完善的工具链
  5. 静态链接
  6. 快速编译
  7. 跨平台
  8. 垃圾回收

2.哪些公司使用Go语言

字节跳动已经全面拥抱了go语言,公司内部有上万个微服务使用golang来编写,不久前也开源了GO RPC框架KiteX。根据拉勾的招聘数据,腾讯、百度、美团、滴滴、深信服、平安、OPPO、知乎、去哪儿、360、 金山、微博、哔哩哔哩、七牛PingCAP 等公司也在大星使用Go语言。国外Google、Facebook等公司也在大量使用Go语言。

二.基础语法

1.变量

Go 语言变量名由字母、数字、下划线组成,其中首个字符不能为数字。声明变量的一般形式是使用 var 关键字。

package main

import (
   "fmt"
   "math"
)

func main() {

   var a = "initial"

   var b, c int = 1, 2

   var d = true

   var e float64

   f := float32(e)

   g := a + "foo"
   fmt.Println(a, b, c, d, e, f) // initial 1 2 true 0 0
   fmt.Println(g)                // initialapple

   const s string = "constant"
   const h = 500000000
   const i = 3e20 / h
   fmt.Println(s, h, i, math.Sin(h), math.Sin(i))
}

2.if else

Go 语言提供了以下几种条件判断语句:

语句描述
if 语句if 语句 由一个布尔表达式后紧跟一个或多个语句组成。
if...else 语句if 语句 后可以使用可选的 else 语句, else 语句中的表达式在布尔表达式为 false 时执行。
if 嵌套语句你可以在 if 或 else if 语句中嵌入一个或多个 if 或 else if 语句。
switch 语句switch 语句用于基于不同条件执行不同动作。
select 语句select 语句类似于 switch 语句,但是select会随机执行一个可运行的case。如果没有case可运行,它将阻塞,直到有case可运行。

注意:Go 没有三目运算符,所以不支持 ?: 形式的条件判断。

go语言里面的if else写法和C或者C++类似。不同点是if后面没有括号。如果你写括号的话,那么在保存的时候你的编辑器会自动把你去掉。第二个不同点是Golang里面的if,它必须后面接大括号,就是不能像C或者C++ 一样,直接把if里面的语句同一行。

package main

import "fmt"

func main() {

   if 7%2 == 0 {
      fmt.Println("7 is even")
   } else {
      fmt.Println("7 is odd")
   }

   if 8%4 == 0 {
      fmt.Println("8 is divisible by 4")
   }

   if num := 9; num < 0 {
      fmt.Println(num, "is negative")
   } else if num < 10 {
      fmt.Println(num, "has 1 digit")
   } else {
      fmt.Println(num, "has multiple digits")
   }
}

3.循环

go语言里面的循环,在go里面没有while循环、do while循环,只有唯一的一种for循环。最简单的for循环就是在for后面什么都不写,代表一个死循环。循环途中可以用break跳出。在循环里面,可以用break或者continue来跳出或者继续循环。

package main

import "fmt"

func main() {

   i := 1
   for {
      fmt.Println("loop")
      break
   }
   for j := 7; j < 9; j++ {
      fmt.Println(j)
   }

   for n := 0; n < 5; n++ {
      if n%2 == 0 {
         continue
      }
      fmt.Println(n)
   }
   for i <= 3 {
      fmt.Println(i)
      i = i + 1
   }
}

4.switch

go语言里面的switch分支结构。看起来也C或者C++比较类似。同样的在switch后面的那个变量名,并不是要括号。

这里有个很大的一点不同的是,在c++里面,switch case如果不显示加break的话会然后会继续往下跑完所有的case,在go语言里面的话是不需要加break的。

相比C或者C++,go语言里面的switch功能更强大。可以使用任意的变量类型,甚至可以用来取代任意的if else语句。你可以在switch后面不加任何的变量,然后在case里面写条件分支。这样代码相比你用多个if else代码逻辑会更为清晰。

package main

import (
   "fmt"
   "time"
)

func main() {

   a := 2
   switch a {
   case 1:
      fmt.Println("one")
   case 2:
      fmt.Println("two")
   case 3:
      fmt.Println("three")
   case 4, 5:
      fmt.Println("four or five")
   default:
      fmt.Println("other")
   }

   t := time.Now()
   switch {
   case t.Hour() < 12:
      fmt.Println("It's before noon")
   default:
      fmt.Println("It's after noon")
   }
}

5.数组

Go 语言提供了数组类型的数据结构。数组是具有相同唯一类型的一组已编号且长度固定的数据项序列,这种类型可以是任意的原始类型例如整型、字符串或者自定义类型。数组就是一个具有编号且长度固定的元素序列。比如这里的话是一个可以存放5个int元素 对于一个数组,可以很方便地取特定索引的值或者往特定索引取存储值,然后也能够直接去打印一个数组。不过,在真实业务代码里面,我们很少直接使用数组,因为它长度是固定的,我们用的更多的是切片。

package main

import "fmt"

func main() {

   var a [5]int
   a[4] = 100
   fmt.Println("get:", a[2])
   fmt.Println("len:", len(a))

   b := [5]int{1, 2, 3, 4, 5}
   fmt.Println(b)

   var twoD [2][3]int
   for i := 0; i < 2; i++ {
      for j := 0; j < 3; j++ {
         twoD[i][j] = i + j
      }
   }
   fmt.Println("2d: ", twoD)
}

6.切片

Go 语言切片是对数组的抽象。Go 数组的长度不可改变,在特定场景中这样的集合就不太适用,Go 中提供了一种灵活,功能强悍的内置类型切片("动态数组"),与数组相比切片的长度是不固定的,可以追加元素,在追加时可能使切片的容量增大。我们可以用make来创建一个切片, 可以像数组一样去取值,使用append来追加元素。

注意append的用法的话,你必须把append的结果赋值为原数组。因为slice的原理实际上是它有一个它存储了一个长度和一个容量,加一个指向一个数组的指针,在你执行append操作的时候,如果容量不够的话,会扩容并且返回新的slice。

package main

import "fmt"

func main() {

   s := make([]string, 3)
   s[0] = "a"
   s[1] = "b"
   s[2] = "c"
   fmt.Println("get:", s[2])   // c
   fmt.Println("len:", len(s)) // 3

   s = append(s, "d")
   s = append(s, "e", "f")
   fmt.Println(s) // [a b c d e f]

   c := make([]string, len(s))
   copy(c, s)
   fmt.Println(c) // [a b c d e f]

   fmt.Println(s[2:5]) // [c d e]
   fmt.Println(s[:5])  // [a b c d e]
   fmt.Println(s[2:])  // [c d e f]

   good := []string{"g", "o", "o", "d"}
   fmt.Println(good) // [g o o d]
}

7.map

Map 是一种无序的键值对的集合。Map 最重要的一点是通过 key 来快速检索数据,key 类似于索引,指向数据的值。

Map 是一种集合,所以我们可以像迭代数组和切片那样迭代它。不过,Map 是无序的,我们无法决定它的返回顺序,这是因为 Map 是使用 hash 表来实现的。 map,在其他编程语言里面, 它可能可以叫做哈希或者字典。map 是实际使用过程中最频繁用到的数据结构。我们可以用make来创建一个空 map,这里会需要两个类型,第一个是那个key的类型,这里是string另一个是value 的类型,这里是int。可以从里面去存储或者取出键值对。可以用delete从里面删除键值对。

golang的map是完全无序的,遍历的时候不会按照字母顺序,也不会按照插入顺序输出,而是随机顺序。

package main

import "fmt"

func main() {
   m := make(map[string]int)
   m["one"] = 1
   m["two"] = 2
   fmt.Println(m)           // map[one:1 two:2]
   fmt.Println(len(m))      // 2
   fmt.Println(m["one"])    // 1
   fmt.Println(m["unknow"]) // 0

   r, ok := m["unknow"]
   fmt.Println(r, ok) // 0 false

   delete(m, "one")

   m2 := map[string]int{"one": 1, "two": 2}
   var m3 = map[string]int{"one": 1, "two": 2}
   fmt.Println(m2, m3)
}

8.函数

Go 语言最少有1个 main() 函数(java叫做方法)。可以通过函数来划分不同功能,逻辑上每个函数执行的是指定的任务。函数声明时告诉了编译器函数的名称、返回类型、参数。

Go 语言标准库提供了多种可动用的内置的函数。例如,len() 函数可以接受不同类型参数并返回该类型的长度。如果我们传入的是字符串则返回字符串的长度,如果传入的是数组,则返回数组中包含的元素个数。

package main

import "fmt"

func add(a int, b int) int {
   return a + b
}

func add2(a, b int) int {
   return a + b
}

func exists(m map[string]string, k string) (v string, ok bool) {
   v, ok = m[k]
   return v, ok
}

func main() {
   res := add(1, 2)
   fmt.Println(res) // 3

   v, ok := exists(map[string]string{"a": "A"}, "a")
   fmt.Println(v, ok) // A True
}