这是我参与「第三届青训营 -后端场」笔记创作活动的第1篇笔记
这篇笔记主要用来回顾GO语言相关的基础语法 包括 变量简单声明 异常处理 通道 结构体方法定义部分
变量声明基本使用
从简单的Hello Go开始吧!
package main
import "fmt"
func main() {
fmt.Println("Hello, world!")
}
package声明所在的包 main包中的main方法为程序的主入口 fmt:标准格式化输入输出
可以使用flag来解析传入程序的参数
使用:=进行快速的声明赋值
func main() {
block := "function"
{
block := "inner"
fmt.Printf("The block is %s.\n", block)
}
fmt.Printf("The block is %s.\n", block)
}
注意块级作用域的存在
go语言中的内置数据结构
map-> Key-Value键值对的形式存在
func main() {
container := map[int]string{0: "zero", 1: "one", 2: "two"}
fmt.Printf("The element is %q.\n", container[1])
}
也可以使用make创建对应的数据结构
重点:Slice GO中切片的含义 其中length capacity Value中有不同的含义
切片可以共享内存地址 修改另一个引用的切片可能会更改其他的源数据(需要注意)
func main() {
// 示例1。
s1 := make([]int, 5)
fmt.Printf("The length of s1: %d\n", len(s1))
fmt.Printf("The capacity of s1: %d\n", cap(s1))
fmt.Printf("The value of s1: %d\n", s1)
s2 := make([]int, 5, 8)
fmt.Printf("The length of s2: %d\n", len(s2))
fmt.Printf("The capacity of s2: %d\n", cap(s2))
fmt.Printf("The value of s2: %d\n", s2)
fmt.Println()
// 示例2。
s3 := []int{1, 2, 3, 4, 5, 6, 7, 8}
s4 := s3[3:6]
fmt.Printf("The length of s4: %d\n", len(s4))
fmt.Printf("The capacity of s4: %d\n", cap(s4))
fmt.Printf("The value of s4: %d\n", s4)
fmt.Println()
// 示例3。
s5 := s4[:cap(s4)]
fmt.Printf("The length of s5: %d\n", len(s5))
fmt.Printf("The capacity of s5: %d\n", cap(s5))
fmt.Printf("The value of s5: %d\n", s5)
}
使用append进行追加 返回的是新的地址 所以需要重新赋值
s7 := make([]int, 1024)
fmt.Printf("The capacity of s7: %d\n", cap(s7))
s7e1 := append(s7, make([]int, 200)...)
异常处理
在Go语言中,错误或异常分为error和panic两种,error一般是程序员可预知的,会进行合适的处理,例如检测输入是否合法等。而panic是程序员无法预知的异常,例如空指针或数组越界等。
Go 提供了两种创建error的方法,分别是: errors.New fmt.Errorf
一般在没有recover的情况下panic会导致程序崩溃,panic,defer和recover经常同时出现,用于异常处理.
func main() {
var m map[string]int
key := "two"
elem, ok := m["two"]
fmt.Printf("The element paired with key %q in nil map: %d (%v)\n",
key, elem, ok)
fmt.Printf("The length of nil map: %d\n",
len(m))
fmt.Printf("Delete the key-element pair by key %q...\n",
key)
delete(m, key)
elem = 2
fmt.Println("Add a key-element pair to a nil map...")
m["two"] = elem // 这里会引发panic。
}
CSP模型
Go中有独特的Channel类型 可以很方便的添加接受数据
使用 <- 即可 很方便的将数据从管道中取出 赋值
func main() {
ch1 := make(chan int, 3)
ch1 <- 2
ch1 <- 1
ch1 <- 3
elem1 := <-ch1
fmt.Printf("The first element received from channel ch1: %v\n",
elem1)
}
chan构造的时候后一个参数指定通道内可以容纳的数据个数
当chan空或者满的时候 执行对应的取 和 添加 会发生阻塞
func main() {
// 示例1。
ch1 := make(chan int, 1)
ch1 <- 1
//ch1 <- 2 // 通道已满,因此这里会造成阻塞。
// 示例2。
ch2 := make(chan int, 1)
//elem, ok := <-ch2 // 通道已空,因此这里会造成阻塞。
//_, _ = elem, ok
ch2 <- 1
// 示例3。
var ch3 chan int
//ch3 <- 1 // 通道的值为nil,因此这里会造成永久的阻塞!
//<-ch3 // 通道的值为nil,因此这里会造成永久的阻塞!
_ = ch3
}
可以通过指定收发类型来创建通道
流程控制Select可以很方便的监听可用通道 执行对应的分支
func example1() {
// 准备好几个通道。
intChannels := [3]chan int{
make(chan int, 1),
make(chan int, 1),
make(chan int, 1),
}
// 随机选择一个通道,并向它发送元素值。
index := rand.Intn(3)
fmt.Printf("The index: %d\n", index)
intChannels[index] <- index
// 哪一个通道中有可取的元素值,哪个对应的分支就会被执行。
select {
case <-intChannels[0]:
fmt.Println("The first candidate case is selected.")
case <-intChannels[1]:
fmt.Println("The second candidate case is selected.")
case elem := <-intChannels[2]:
fmt.Printf("The third candidate case is selected, the element is %d.\n", elem)
default:
fmt.Println("No candidate case is selected!")
}
}
声明方法
使用type 方法名 func(参数列表) 返回值 的方式定义方法
type operate func(x, y int) int
// 方案1。
func calculate(x int, y int, op operate) (int, error) {
if op == nil {
return 0, errors.New("invalid operation")
}
return op(x, y), nil
}
// 方案2。
type calculateFunc func(x int, y int) (int, error)
func genCalculator(op operate) calculateFunc {
return func(x int, y int) (int, error) {
if op == nil {
return 0, errors.New("invalid operation")
}
return op(x, y), nil
}
}
定义结构体
使用type 类型名 struct{字段}定义 结构体
支持结构体之间的组合
当声明对象时 可以使用 对象名:=结构体名{对应字段} 的方式创建对象
package main
import "fmt"
// 示例1。
// AnimalCategory 代表动物分类学中的基本分类法。
type AnimalCategory struct {
kingdom string // 界。
phylum string // 门。
class string // 纲。
order string // 目。
family string // 科。
genus string // 属。
species string // 种。
}
func (ac AnimalCategory) String() string {
return fmt.Sprintf("%s%s%s%s%s%s%s",
ac.kingdom, ac.phylum, ac.class, ac.order,
ac.family, ac.genus, ac.species)
}
// 示例2。
type Animal struct {
scientificName string // 学名。
AnimalCategory // 动物基本分类。
}
// 该方法会"屏蔽"掉嵌入字段中的同名方法。
func (a Animal) String() string {
return fmt.Sprintf("%s (category: %s)",
a.scientificName, a.AnimalCategory)
}
// 示例3。
type Cat struct {
name string
Animal
}
// 该方法会"屏蔽"掉嵌入字段中的同名方法。
func (cat Cat) String() string {
return fmt.Sprintf("%s (category: %s, name: %q)",
cat.scientificName, cat.Animal.AnimalCategory, cat.name)
}
func main() {
// 示例1。
category := AnimalCategory{species: "cat"}
fmt.Printf("The animal category: %s\n", category)
// 示例2。
animal := Animal{
scientificName: "American Shorthair",
AnimalCategory: category,
}
fmt.Printf("The animal: %s\n", animal)
// 示例3。
cat := Cat{
name: "little pig",
Animal: animal,
}
fmt.Printf("The cat: %s\n", cat)
}