Go 语言基础
这是我参与「第五届青训营 」伴学笔记创作活动的第 1 天
1 简介
1.1 什么是 Go 语言
- 高性能、高并发
- 语法简单、学习曲线平缓
- 丰富的标准库
- 完善的工具链
- 静态链接
- 快速编译
- 跨平台
- 垃圾回收
1.2 字节为什么全面拥抱 Go 语言
- 最初使用的 Python,由于性能问题换成了 Go
- C++ 不太适合在线 Web 业务
- 早期团队非 Java 背景
- 性能比较好
- 部署简单、学习成本低
- 内部 RPC 和 HTTP 框架的推广
2 入门
2.1 基础语法 - 变量
go 语言是一门强类型语言,每一个变量都有它自己的变量类型。常见的变量类型包括字符串整数浮点型、布尔型等。go语言的字符串是内置类型,可以直接通过加号拼接,也能够直接用等于号去比较两个字符串。在 go 语言里面,大部分运算符的使用和优先级都和 C 或者 C++ 类似,这里就不再概述。
下面讲述 go 语言里面的变量的声明,在 go 语言里面变量的声明有两种方式,一种是通过 var name string = "" 这种方式来声明变量,声明变量的时候,一 般会自动去推导变量的类型。如果有需要,也可以显示写出变量类型。另一种声明变量的方式是使用 变量 := 值。
下面来说说常量,就是将 var 改成 const,它没有确定的类型,会根据使用的上下文自动确定类型。
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.2 基础语法 - if else
接下来介绍 go 语言里面的 if else。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")
}
}
2.3 基础语法 - 循环
下面讲述 go 语言里面的循环,在 go 里面没有 while 循环、do while 循环,只有唯一的一 种 for 循环。最简单的 for 循环就是在 for 后面什么都不写,代表一个死循环。循环途中你可以用 break 跳出,也可以使用经典的 C 循环,就是 for l=0;l<n;l++。这中间三段,任何一段都可以省略。
在循环里面,你可以用 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
}
}
2.4 基础语法 - switch
下面是关于 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")
}
}
2.5 基础语法 - 数组
数组就是一个具有编号且长度固定的元素序列。 比如这里的话是对于一个数组, 可以很方便地取特定索引的值或者往特定索引取存储值,然后也能够直接去打印一个数组。 不过,在真实业务代码里面,我们很少直接使用数组,因为它长度是固定的,我们用的更多的是切片。
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)
}
2.6 基础语法 - 切片
切片不同于数组可以任意更改长度,然后也有更多丰富的操作。比如说我们可以用 make 来创建一个切片, 可以像数组-样去取值, 使用 append 来追加元素。注意 append 的用法的话,你必须把 append 的结果赋值为原数组。因为 slice 的原理实际上是它有一个它存储了一个长度和一个容量,加一个指向一个数组的指针,在你执行 append 操作的时候,如果容量不够的话,会扩容并且返回新的 slice。slice 此初始化的时候也可以指定长度。
slice 拥有像 python 一样的切片操作,比如这个代表取出第二个到第五个位置的元素,不包括第五个元素。不过不同于 python,这里不支持负数索引。
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]
}