一、前言
1.1 统一思想
1.2 为什么需要学Go语言
Go语言的优势
Go语言不支持的特性
Go语言特性衍生来源
二、实践
2.1 Go语言编译环境设置
2.2 控制结构
if
- 基本形式
//基本写法
if condition1 {
//do something
} else if condition2 {
//do something
} else {
//catch-all or default
}
//if 简短语句
if v:=x - 100;v<0{
return v
}
- switch
switch var1 {
case val1://空分支
case val2:
fallthrough//执行case3中的f()
case val3:
f()
default: //默认分支
……
}
- for
//go语言只有一种循环:for
for i:=0;i<10;i++ {
sum += i
}
//无限循环
for {
if condition1 {
break
}
}
2.3 Go语言常用数据结构
常量和变量
- 常量 const identifier type
- 变量 var identifier type
//变量
var c, python, java bool
//变量初始化
var i,j int = 1,2
//短变量声明
c, python, java := true,false,"no!"
// := 可在函数内使用
类型转化和推导
// 数值转化
var i int = 42
var f float64 = float64(i)
var u uint = uint(f)
//类型推导
var i int;
j := i //j和i相等 j也是int
数组
//定义
var identifier[len] type
array :=[3]int{1,2,3}
//demo
func main() {
array := [3]int{1, 2, 3}
fmt.Println(array)
fmt.Println("=========================")
//=========================
for i := 0; i < len(array); i++ {
fmt.Println(array[i])
}
fmt.Println("=========================")
//==========================
array2 := [3]int{}
for i := 0; i < len(array); i++ {
array2[i] = i
}
fmt.Println(array)
}
切片
- 切片是对数组一个连续片段的引用
- 数组定义中不指定长度即为切片
- var identifier []type
- 切片在未初始化之前默认为nil, 长度为0
- 常用方法
func main() {
array := [5]int{1, 2, 3, 4, 5}
slice := array[1:3]
fmt.Printf("slice %+v\n", slice)
fullSlice := array[:]
result := deleteItem(fullSlice, 2)
fmt.Printf("result: %+v\n", result)
var slice2 []int
slice2 = append(slice2, 1)
slice2 = append(slice2, 2)
fmt.Printf("slice2: %+v\n", slice2)
}
func deleteItem(slice []int, index int) []int {
return append(slice[:index], slice[index+1:]...)
}
//构建切片
func main() {
//new 返回指针地址
//make 返回第一个元素,可预设内存空间,避免未来的内存拷贝
slice := new([]int)
slice2 := make([]int, 0)
slice3 := make([]int, 10)
slice4 := make([]int, 10, 20)
fmt.Println(slice)
fmt.Println(slice2)
fmt.Println(slice3)
fmt.Println(slice4)
}
Map
func main() {
//简单map
myMap := make(map[string]string, 10)
myMap["key1"] = "a"
fmt.Println(myMap)
//复杂
myFuncMap := map[string]func() int{
"funA": func() int {
return 1
},
}
fmt.Println(myFuncMap)
//访问map
value, exists := myMap["key1"]
if exists {
println(value)
}
for k, v := range myMap {
println(k, v)
}
}
结构体
func main() {
s1 := Student{}
p1 := &s1 //取指针地址
student := *p1 //取值
fmt.Println(student)
s := new(Student) //new 出来直接是指针地址
fmt.Println(*s)
s.name = "nike"
s.age = 18
name := getName(*s)
fmt.Println(name)
}
type Student struct {
name string
age int
}
func getName(student Student) string {
return student.name
}
type IF interface {
getName() string
}
结构体标签
// MyType k8s APIServer 对所有资源的定义都用了json tag 和 protoBuff tag
type MyType struct {
Name string `json:"name"`
}
func main() {
mt := MyType{Name: "test"}
myType := reflect.TypeOf(mt)
name := myType.Field(0)
tag := name.Tag.Get("json")
println(tag)
}
类型别名
类似于枚举
2.4 Go语言函数调用
init 函数
import (
_ "GoDemoProject/src/MethodDemo/initDemo/a"
_ "GoDemoProject/src/MethodDemo/initDemo/b"
"fmt"
)
// init 只执行一次
func init() {
fmt.Println("init main")
}
func main() {
fmt.Println("main")
}
package a
import (
_ "GoDemoProject/src/MethodDemo/initDemo/b"
"fmt"
)
func init() {
fmt.Println("a")
}
package b
import "fmt"
func init() {
fmt.Println("b")
}
返回值
package main
import "fmt"
func main() {
err, result := method("bbb")
if err == nil {
fmt.Println(result)
} else {
fmt.Println(err)
}
}
func method(input string) (err error, result string) {
if input == "aaa" {
err = fmt.Errorf("aaa is not allowed")
return
}
result = input + input
return nil, result
}
传递变长的参数
func main() {
var array []string
array = append(array, "a", "b", "c")
for index, value := range array {
println(index, value)
}
}
内置函数
回调函数 callback
- 函数作为参数传入其他函数,并在其他函数内部调用执行
- strings.indexFunc(line, unicode.isSpace)
- kubernetes controller的leaderelection
func main() {
DoOperation(1, increase)
DoOperation(1, decrease)
}
func increase(a, b int) {
println("i result:", a+b)
}
func decrease(a, b int) {
println("d result:", a-b)
}
func DoOperation(y int, f func(int, int)) {
f(y, 1)
}
闭包
- 匿名函数
- 可以赋值给其他变量
- x:=func(){}
- 可以直接调用
- func(x,y int){println(x+y)}(1,2)
- 可作为函数返回值
- func Add() (func(b int)int)
全局变量的特点:1.常驻内存 2. 污染全局
局部变量的特点:1.不常驻内存 2.不污染全局
而Go语言的闭包可以做到: 1.可以让变量常驻内存 2.可以让变量不污染全局
闭包
1.闭包是指有权访问另一个函数作用域中的变量的函数
2.创建闭包的常见方式就是在一个函数内部创建另一个函数, 内函数可以访问外函数的变量
注意:
闭包里作用域返回的局部变量不会被立刻销毁回收,但过度使用闭包可能会占用更多内存,导致性能下降。
func main() {
result := add(1)
println(result())
}
func add(a int) func() int {
i := a + a
return func() int {
return i + 1
}
}
方法
方法:作用在接收者上的函数
- func(recv receiver_type) methodName(parameter_list)(return_value_list)
- 使用场景
- 很多场景下,函数需要的上下文可以保持在recevier属性中,通过定义recevier方法,该 方法可以直接访问recevier属性,减少参数传递需求
type Student struct {
name string
age int
}
func (s Student) notify() {
fmt.Printf("%v : %v \n\n", s.name, s.age)
}
func main() {
//值调用
s1 := Student{"jack", 18}
s1.notify()
//指针调用
s2 := Student{"rose", 16}
(&s2).notify()
}
接口
type IF interface {
getName() string
}
type Student struct {
name string
age int
}
func (s *Student) getName() string {
return s.name
}
type Car struct {
factory, model string
}
func (c *Car) getName() string {
return c.factory + "-" + c.model
}
func main() {
var interfaces []IF
student := new(Student)
student.name = "jack"
student.age = 18
interfaces = append(interfaces, student)
car := new(Car)
car.factory = "benz"
car.model = "s"
interfaces = append(interfaces, car)
for _, f := range interfaces {
fmt.Println(f.getName())
}
}
反射机制
type Student struct {
name string
age int
}
func (s Student) getName() string {
return s.name
}
func main() {
myMap := make(map[string]string, 10)
myMap["A"] = "aaa"
t := reflect.TypeOf(myMap)
fmt.Println("type:", t)
v := reflect.ValueOf(myMap)
fmt.Println("value", v)
//基于struct的反射
student := Student{"jack", 18}
v1 := reflect.ValueOf(student)
for i := 0; i < v1.NumField(); i++ {
fmt.Printf("Filed %d: %v\n", i, v1.Field(i))
}
for i := 0; i < v1.NumMethod(); i++ {
fmt.Printf("Method %d: %v\n", i, v1.Method(i))
}
}