这是我参与「第五届青训营 」伴学笔记创作活动的第 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后面不需要加括号,大括号需要再同一行。
循环类型:
- if后面什么都不加是死循环
- 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遍历的时候,对于数组会返回两个值,第一个是索引,第二个是对应位置上的值,如果不需要索引的话,可以使用下划线来忽略。