GO语言基础 | 青训营笔记

37 阅读6分钟

这是我参与「第五届青训营 」伴学笔记创作活动的第 1 天,本文用于记录在青训营的学习笔记和一些心得。

1. Go语言简介

GO是一个高性能、高并发、语法简单、学习曲线平缓、拥有丰富的标准库、完善的工具链、可以静态链接、快速编译、支持跨平台、垃圾回收的语言。目前大多数公司都在使用go语言,字节跳动已经全面使用 go 语言,上万个微服务使用 golang 来编写,不久前也开源了 GO RPC 框架 KiteX。国内腾讯、百度、美团等公司也在大量使用 Go 语言。国外 Google Facebook 等公司也在大量使用 Go 语言。

2. Go语言基础

变量

 package main
 ​
 import (
     "fmt"
 )
 func main(){
     //变量定义: var 变量名 类型
     var a int
     a = 10
     fmt.Println("a = ",a)
     //连续声明格式
     var a1,a2 int = 0,1
     fmt.Printf("a1 = %d   a2 = %d",a1,a2)
 ​
     //变量的初始化
     //1.声明之后使用等号赋值
     var b1 int = 10
     //2.使用:=自动推导
     b2 := 20
     fmt.Println("b1 = ",b1,"b2 = ",b2)
 ​
     //常量的初始化
     const c int = 1000
     fmt.Println("c = ",c)
 }

go语言的字符串是内置类型,可以直接通过加号拼接,也能够直接用等于号去比较两个字符串。在go语言里面,大部分运算符的使用和优先级都和C或者C++类似

Go语言里面的变量的声明,在Go语言里面变量的声明有两种方式,一种是通过”vae name 类型“这种方式来声明变量,声明变量的时候,一般会自动推导变量的类型,如果有需要,你可以显示的写出变量类型,另一种声明变量的方式是使用变量冒号:=等于值。

常量的话就是把var改成const,值在一提的是go语言里面的常量,它没有确定的类型,会根据使用的上下文来自动确定类型。

条件结构

 package main
 ​
 import "fmt"
 ​
 func main() {
 ​
     //注意点:
     //1.if/else后需要跟{ 不然报错:syntax error: unexpected newline, expecting { after if clause
     //2.if条件不需要加括号
     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 { //初始化num = 9,然后进行判断
         fmt.Println(num, "is negative")
     } else if num < 10 {
         fmt.Println(num, "has 1 digit")
     } else {
         fmt.Println(num, "has multiple digits")
     }
 }

go语言的条件结构与c++类似

不同点1: if 后面不需要加括号,如果加了编译器会自动去掉

不同点2: if后面必须跟上大括号

循环结构

 package main
 ​
 import "fmt"
 ​
 func main() {
 ​
 ​
 ​
     //for循环后面不跟条件,即为死循环
     for {
         fmt.Println("loop")
         break
     }
 ​
     //for后面的条件不需要加括号
     for j := 7; j < 9; j++ {
         fmt.Println(j)
     }
 ​
     //for循环嵌套if条件句
     for n := 0; n < 5; n++ {
         if n%2 == 0 {//如果是偶数,跳过输出,进入下一次循环
             continue
         }
         fmt.Println(n)
     }
 ​
     //初始化变量i
     i := 1
     for i <= 3 {
         fmt.Println(i)
         i = i + 1
     }
     
 }

Go里面只有一个for循环,for后面不需要加括号,大括号需要再同一行。

循环类型:

  1. if后面什么都不加是死循环
  2. for循环可以通过break来跳出

switch语句

 package main
 ​
 import (
     "fmt"
     "time"
 )
 ​
 func main() {
 ​
     //switch的case语句中不需要添加break,当某一句执行结束之后会自动break
     //switch后条件不需要加括号
     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")
     }
 ​
     //swith的参数可以是任意类型,故switch可替换ifelse语句
     t := time.Now()
     switch {
     case t.Hour() < 12:
         fmt.Println("It's before noon")
     default:
         fmt.Println("It's after noon")
     }
 }
 ​

go语言里面的 switch分支结构同样在switch后面的那个变量名,并不需要括号。

在c++里面,switch case如果不加 break的话会然后会继续往下跑完所有的case,在go语言里面的话是不需要加 break的,执行完case语句之后会直接跳出。

Go语言中,switch的参数可以是各种类型的,可以取代 if else语句:你可以在switch后面不加任何的变量,然后在case里面写条件分支。这样代码相比你用多个if else代码逻辑会更为清晰。

数组

 package main
 ​
 import "fmt"
 ​
 func main(){
     //一维数组声明
     var arr[5] int
     //可以通过数组下标给数组元素赋值
     arr[4] = 10
     //未被赋值的元素初始化成0
     fmt.Println("arr[2] =", arr[2])
     fmt.Println("arr[4] =", arr[4])
 ​
     //使用len()来获取数组的长度
     fmt.Println("length of array:", len(arr))
 ​
     //使用自动推导来创建一维数组
     b := [5]int{1, 2, 3, 4, 5}
     fmt.Println(b) //数组的输出也可以直接使用println 输出[1 2 3 4 5]
 ​
     //二维数组声明
     var towarr[3][3] int
     for i := 0; i < 3; i++ {
         for j := 0; j < 3; j++ {
             towarr[i][j] = i + j
         }
     }
     //二维数组的输出类似与一维数组的输出
     fmt.Println("towarr: ", towarr)
 ​
 }
 ​
 ​

数组就是一个具有编号且长度固定的元素序列。比如这里的话是一个可以存放5个int元素的数组A。对于一个数组,可以很方便地取特定索引的值或者往特定索引取存储值,然后也能够直接去打印一个数组。不过,在真实业务代码里面,我们很少直接使用数组,因为它长度是固定的,我们用的更多的是切片。

切片

 package main
 ​
 import "fmt"
 ​
 func main(){
     //slice的声明
     s := make([]string, 3)
     s[0] = "hello"
     s[1] = "world"
     s[2] = "!"
 ​
     //输出某一元素和整个slice内容
     fmt.Println("s[1] =", s[1])   // hello
     fmt.Println("s =",s)
     //获取slice长度
     fmt.Println("len:", len(s)) // 3
 ​
     //向slice中添加扩展
     //使用append函数,注:返回值一定要指向本身
     s = append(s, "leo")
     fmt.Println("s =",s)
 ​
     //slice的拷贝(大小相同,然后拷贝)
     c := make([]string, len(s))
     copy(c, s)//从s里面拷贝到c里面
     fmt.Println("c = ",c)
 ​
     //slice的部分元素输出
     fmt.Println(s[2:4]) // [! leo] 输出下标2,3元素
     fmt.Println(s[:3])  // [hello world !] 输出下标 0 - 2元素
     fmt.Println(s[1:])  // [world ! leo] 从下表1开始输出到文件的末尾
 ​
     //slice的自动推导的声明
     good := []string{"g", "o", "o", "d"}
     fmt.Println(good) // [g o o d]
 }
 ​

切片不同于数组,可以任意更改长度,然后也有更多丰富的操作。比如说我们可以用make来创建一个切片,可以像数组一样去取值,使用append 来追加元素。注意append的用法的话,你必须把 append的结果赋值为原数组。

因为 slice 的原理实际上是它有一个它存储了一个长度和一个容量,加一个指向一个数组的指针,在你执行append操作的时候,如果容显不够的话,会扩容并且返回新的 silce,slice 初始化的时候也可以指定长度。 slice拥有像python一样的切片操作,比如这个代表取出第二个到第五个位置的元素,不包括第五个元素。不过不同于python,这里不支持负数索引。

range

 package main
 ​
 import "fmt"
 ​
 func main(){
 ​
     nums := []int{1,2,3,4}
     sum := 0;
     //遍历nums切片并求和
     for i,nums := range nums{
         sum += nums
         if nums == 2 {
             fmt.Println("index:", i, "num:", nums) // index: 0 num: 2
         }
     }
 ​
     fmt.Println("sum = ",sum) // 10
 ​
     m := map[string]string{"a": "A", "b": "B"}
     //遍历键值对
     for k,v := range m{
         fmt.Println(k, v) // b 8; a A
     }
 ​
     //只遍历键
     for k := range m {
         fmt.Println("key : ",k) // b 8; a A
     }
 }

对于一个slice和map,我们可以使用range来遍历,这样可以使代码更加简洁。range遍历的时候,对于数组会返回两个值,第一个是索引,第二个是对应位置上的值,如果不需要索引的话,可以使用下划线来忽略。