go基础语法 | 青训营笔记

91 阅读2分钟

这是我参与「第三届青训营 -后端场」笔记创作活动的的第5篇笔记,主要介绍了go语言的基础语法。

go语言

1.数组

  • 数组的声明
a :=[3]int{1,23,3}
b:=[...]int{7,6,4,45,2,3,5,}
var c=new([5]int)
c[4]=3
  • 驻足的遍历
for i,v :=range(zoom){
    fmt.Print(i,v)
}
  • 切片

切片是数组的一部分,是对原来数组的复用

a :=[3]int{1,23,3}
c1:=a[1:]
c1=append(c1,5)//可以通过这种方式对切片进行扩容,原数组不扩容,理解复用的意思
c1[0]=4
c1//[4,3,5] 扩容后与原数组无关 ,每次扩容为原来的2倍
a //[1,23,3]

a := [3]int{0, 1, 2}
cl := a[:] //[0,1,2]
c := a[2:]
cl = append(cl, 5)
copy(cl, c)
fmt.Print(cl)//[2,1,2,5] 把后面的拷到前面的位置
copy(cl[1:2],c)//可以指定复制的位置,如果不指定,则从前面开始覆盖

//一般的创建方式  4为length,6为cap,可以不指定cap
aaa:=make([]int,4,6)//这种方式出来的切片有默认值[0,0,0,0]
var aa []int //这种方式出来的切片为空

2.通道

1.通道的使用

  • 无缓存通道
func main() {
	c := make(chan int) //创建无缓存的通道
	var writec chan<- int = c
	var readc <-chan int = c
	go Write(writec)
	Read(readc)
}
func Write(writec chan<- int) {
	for i := 0; i < 10; i++ {
		writec <- 1
	}
}
func Read(readc <-chan int) {
	for i := 0; i < 10; i++ {
		fmt.Println("我在取数据", <-readc)
	}
}
  • 有缓存通道
func main() {
	var c = make(chan int, 1)
	c <- 1
	fmt.Println(<-c)
}

3.结构体

接口可以接收所有实现它的类,所有对interface的调用,本质是对实现类的调用

1.实现接口时类的方法为指针类型

type Person interface {
	Eat()
	Run()
}
type Student struct {
	Name string
}
type Teacher struct {
	Name string
	Uid  int64
}

func (t *Teacher) Eat() {
	fmt.Println("老师会吃----")
}
func (t *Teacher) Run() {
	fmt.Println("老师会跑----")
}
func main() {
	var c Person
    //所有对interface的调用,本质是(&t).Run()
    //go自动处理了指针的问题,但interface变量赋值不会自动处理
	t := &Teacher{"张三", 1}
	c = t
	c.Run()
}

2.实现接口时类的方法为非指针类型

type Person interface {
	Eat()
	Run()
}
type Student struct {
	Name string
}
type Teacher struct {
	Name string
	Uid  int64
}

func (t Teacher) Eat() {
	fmt.Println("老师会吃----")
}
func (t Teacher) Run() {
	fmt.Println("老师会跑----")
}
func main() {
	var c Person
	t := Teacher{"张三", 1}
	c = t
	c.Run()
}

3.泛型和多态

var P Person

type Person interface {
	Eat()
	Run()
}
type Student struct {
	Name string
}
type Teacher struct {
	Name string
	Uid  int64
}

func (t Teacher) Eat() {
	fmt.Println("老师会吃----")
}
func (t Teacher) Run() {
	fmt.Println("老师会跑----")
}
func (s Student) Eat() {
	fmt.Println("老师会吃----")
}
func (s Student) Run() {
	fmt.Println("老师会跑----")
}
func test(p Person) {
	P = p
}
func main() {
	t := Teacher{"张三", 1}
	test(t)
	P.Eat()
}

4.struct类型名的获取

func main() {
	i := 1
	fmt.Println("i type name", reflect.TypeOf(i).Name())
	fmt.Println("i type kind", reflect.TypeOf(i).Kind())

	u := User{Name: "poloxue"}
	fmt.Println("u type name", reflect.TypeOf(u).Name())
	fmt.Println("u type kind", reflect.TypeOf(u).Kind())

	//if reflect.TypeOf(u).Kind() == reflect.Struct {
	//	fmt.Println("u kind is struct")
	//}
	//if reflect.TypeOf(u).Kind() == "User" {
	//	fmt.Println("u type is User")
	//}
}

4.goroutine

WaitGroup使主程序在子程序执行完后关闭,优雅的控制结束时间

func main() {
	wg := sync.WaitGroup{}
	wg.Add(10)
	go func() {
		for i := 0; i < 10; i++ {
			fmt.Println(i)
			wg.Done()
		}
	}()
    fmt.Println("我结束啦")
	wg.Wait()
}

5.断言

把空接口断言为一个结构体,隐含的意思是每个结构体都实现了空接口。

其实就是将空接口强制类型转换为某个对象的实例

type User struct {
	Name string
	Age  int
}
type Student struct {
	Class string
	User
}

func (u User) SayName(name string) {
	fmt.Println("我是" + name)
}
func check(v interface{}) {
	//v.(User).sayName(v.(User).Name)
	switch v.(type) {
	case User:
		fmt.Println("我是User")
		fmt.Println(v.(User).Name)
	case Student:
		fmt.Println("我是Student")
		fmt.Println(v.(Student).Class)
	}
}
  • 断言是使用方式

1.取值函数

func check(inte interface{}) {
	t := reflect.TypeOf(inte)  //main.User
	v := reflect.ValueOf(inte) //{张三 10}
	ty := t.Kind()             //得到类型
	if ty == reflect.Struct {
		fmt.Println("我是struct")
	}
	if ty == reflect.String {
		fmt.Println("我是String")
	}
	if ty == reflect.Int {
		fmt.Println("我是Int")
	}
	//for i := 0; i < t.NumField(); i++ {
	//	fmt.Println(v.Field(i)) //用来获取值
	//}
	fmt.Println(t, v)
	fmt.Println(v.FieldByName("Class"))
	fmt.Println(v.FieldByIndex([]int{1, 0})) //传入一个数组,指示一个层级索引,
	// 取第一位个元素的第零位的值
}

2.修改原始数据

func check(inte interface{}) {
	//t := reflect.TypeOf(inte)  //main.User
	v := reflect.ValueOf(inte) //{张三 10}
	e := v.Elem()
	e.FieldByName("Class").SetString("四年二班")
	fmt.Println(inte)
}
func main() {
	u := User{"张三", 10}
	s := Student{"三年二班", u}
    //要修改原来的值,这一定传的是地址值
    //&取地址 *取值
	check(&s)
	fmt.Println(s)
}

3.调用方法

//函数名大写,否则不能通过反射调用
func (u User) SayName(name string) {
	fmt.Println("我是" + name)
}
func check(inte interface{}) {
	//t := reflect.TypeOf(inte)  //main.User
	v := reflect.ValueOf(inte) //{张三 10}
	m := v.Method(0)
	m.Call([]reflect.Value{reflect.ValueOf("大奇妙")})
}

6.并发编程

1.锁(简单)

2.读写锁

读写互斥 ,读不会互斥

func Recure(lock *sync.RWMutex) {
   lock.RLock()
   fmt.Println("疯狂治疗")
   lock.RUnlock()
}
func GuaSha(lock *sync.RWMutex) {
   lock.Lock()
   fmt.Println("疯狂刮痧")
   lock.Unlock()
}
func main() {
   lock := sync.RWMutex{}
   for i := 0; i < 4; i++ {
      go GuaSha(&lock)
   }
   for i := 0; i < 4; i++ {
      go Recure(&lock)
   }
   for {
   }
}

3.有且只执行一次

func main() {
   o := sync.Once{}
   for i := 0; i < 10; i++ {
      o.Do(func() {
         fmt.Println(i)
      })
   }
}

4.安全并发的map

1.并发存取
func main() {
   wg := sync.WaitGroup{}
   wg.Add(2)
   m := &sync.Map{}
   go func() {
      for {
         fmt.Println("我存进去了")
         m.Store(1, 1)
      }
      wg.Done()
   }()
   go func() {
      for {
         fmt.Println(m.Load(1))
      }
      wg.Done()
   }()
   wg.Wait()
}
2.存后遍历
func main() {
   m := sync.Map{}
   m.Store(1, 1)
   m.Store(1, 2)
   m.Store(2, 1)
   m.Range(func(key, value any) bool {
      fmt.Println(key, value)
      return true //如果返回false,则停止,只有得到true的返回值才能继续遍历
   })

5.并发池

是个池子,可以从里面存取东西,没了的话,取出nil

func main() {
   p := sync.Pool{}
   p.Put(1)
   p.Put(2)
   p.Put(3)
   p.Put(4)
   p.Put(5)
   for i := 0; i < 6; i++ {
      fmt.Println(p.Get())
   }

}
************运行结果***************
1
5    
4    
3    
2    
<nil>

6.Cond 信号量

判断 操作 通知

func Print1(wg *sync.WaitGroup) {
   lock.Lock()
   for {
      if number != 1 {
         co1.Wait() //会释放锁
      } else {
         break
      }
   }
   for i := 0; i < 5; i++ {
      fmt.Println("我来打印1")
   }

   number = 2
   co2.Signal()
   lock.Unlock()
   wg.Done()
}

func Print5(wg *sync.WaitGroup) {
   lock.Lock()
   for {
      if number != 2 {
         co2.Wait() //会释放锁
      } else {
         break
      }
   }
   for i := 0; i < 10; i++ {
      fmt.Println("我来打印2")
   }

   number = 3
   co3.Signal()
   lock.Unlock()
   wg.Done()
}
func Print10(wg *sync.WaitGroup) {
   lock.Lock()
   for {
      if number != 3 {
         co3.Wait() //会释放锁
      } else {
         break
      }
   }
   for i := 0; i < 5; i++ {
      fmt.Println("我来打印3")
   }

   number = 3
   co1.Signal()
   lock.Unlock()
   wg.Done()
}

//第一个程序打印1打印五次之后,再打印2 10次,再打印3 5次
func main() {
   wg := sync.WaitGroup{}
   wg.Add(3)
   go Print1(&wg)
   go Print5(&wg)
   go Print10(&wg)
   wg.Wait()
}