Go by Example 代码记录


代码和理解

结构体

package main

import "fmt"

type Circle struct {
    
    
	radius float64
}

func main() {
    
    
	var c1 Circle
	c1.radius = 10.00
	fmt.Println("面积", c1.getArea())
}

func (c Circle) getArea() float64 {
    
    
	return 3.14 * c.radius * c.radius
}

Struct Embedding

内嵌结构体

package main

import "fmt"

type basin struct {
    
    
	num int
}
type Top struct {
    
    
	basin
	name string
}

func (b basin) showBasin() string {
    
    
	return fmt.Sprintf("showBasin : %v", b.num)
}
func (t Top) showTop() {
    
    
	fmt.Println(t.name)
}
func myFuc(a int) {
    
    
	fmt.Println("hello", a)
}
func main() {
    
    
	co := Top{
    
    
		basin: basin{
    
    
			num: 1,
		},
		name: "大嘴猴",
	}
	ao := new(basin)
	fmt.Println("this is ao")
	fmt.Println(ao)
	fmt.Println(co.showBasin())
	co.showTop()
}

注意到 结构体到函数普通函数 的不同
结构体的初始化 通过 花括号键值对

Generics

泛型

package main

import (
	"errors"
	"fmt"
)

func MapKeys[K comparable, V any](m map[K]V) []K {
    
    
	r := make([]K, 0, len(m))
	for k := range m {
    
    
		r = append(r, k)
	}
	return r
}

type List[T any] struct {
    
    
	head, tail *element[T]
}

type element[T any] struct {
    
    
	next *element[T]
	val  T
}

func (lst *List[T]) Push(v T) {
    
    
	if lst.tail == nil {
    
    
		lst.head = &element[T]{
    
    val: v}
		lst.tail = lst.head
	} else {
    
    
		lst.tail.next = &element[T]{
    
    val: v}
		lst.tail = lst.tail.next
	}
}

func (lst *List[T]) GetAll() []T {
    
    
	var elems []T
	for e := lst.head; e != nil; e = e.next {
    
    
		elems = append(elems, e.val)
	}
	return elems
}

func (lst *List[T]) getFirst() error {
    
    
	if lst.head == nil {
    
    
		return errors.New("空的")
	}
	return nil
}
func main() {
    
    
	var m = map[int]string{
    
    1: "2", 2: "4", 4: "8"}

	fmt.Println("keys:", MapKeys(m))

	a := MapKeys[int, string](m)
	//a := MapKeys(m)
	for _, v := range a {
    
    
		fmt.Println(v)
	}
	fmt.Println("-----------")
	//_ = MapKeys(m)

	lst := List[int]{
    
    }
	lst.Push(10)
	lst.Push(13)
	lst.Push(23)
	fmt.Println("list:", lst.GetAll())

	mList := List[string]{
    
    }
	errr := mList.getFirst()
	fmt.Println("error is : ", errr)
}

管道同步

package main

import "fmt"

func main() {
    
    
	jobs := make(chan int, 5)
	done := make(chan bool)

	go func() {
    
    
		for {
    
    
			j, more := <-jobs
			if more {
    
    
				fmt.Println("还有job ", j)
			} else {
    
    
				fmt.Println("已经收到所有的jobs")
				done <- true
                	// 这里done <- false 的话也可以使得程序结束 
                	// 但是 如果done没有收到 bool值 那么程序会 死锁 
				return
			}
		}
	}()

	for j := 1; j <= 3; j++ {
    
    
		jobs <- j + 10
		fmt.Println("发送 job ", j)
	}
	close(jobs)
	fmt.Println("所有jobs都发送了")

	//<-done
    // 最后一句 <- done 使得程序等待接收  没等到值就会死锁
}

上述代码中有个 more 的变量, 指的是 管道中是否还有值, 如果more为真,说明管道还有值;如果为假, 说明管道没有值了,输出已经收到所有的jobs!
close(jobs)

关闭 一个通道意味着不能再向这个通道发送值了。 该特性可以向通道的接收方传达工作已经完成的信息。

Timer

package main

import (
	"fmt"
	"time"
)

func main() {
    
    
	timer1 := time.NewTimer(2 * time.Second)
	<-timer1.C
	fmt.Println("Timer 1 fired!")

	timer2 := time.NewTimer(time.Second)
	go func() {
    
    
		<-timer2.C
		println("Timer 2 fired!")
	}()
	time.Sleep(2 * time.Second)
	stop2 := timer2.Stop()
	println("stop2 : ", stop2)
	if stop2 {
    
    
		fmt.Println("Timer 2 stopped")
	}
	time.Sleep(2 * time.Second)
}
/*
Timer 1 fired!
Timer 2 fired!
stop2 :  false
*/

通过 time.NewTimer() 来创造一个新的计时器, timer1.C 是 计时器结构体中的一个通道,只有当计时器到时间的时候才会往timer1.C中传值, 所有通过接收<-timer1.C 来等待。

timer.Stop()可以将还没有发生的timer暂停, 会返回一个bool值来表示该计时器在stop之前是否已经停止

如下例子

package main

import (
	"fmt"
	"time"
)

func main() {
    
    
	timer1 := time.NewTimer(2 * time.Second)

	<-timer1.C
	fmt.Println("Timer 1 fired!")

	timer2 := time.NewTimer(time.Second)
	go func() {
    
    
		<-timer2.C
		println("Timer 2 fired!")
	}()
	// time.Sleep(2 * time.Second)  
	stop2 := timer2.Stop()
	println("stop2 : ", stop2)
	if stop2 {
    
    
		fmt.Println("Timer 2 stopped")
	}

	time.Sleep(2 * time.Second)
}
/*
Timer 1 fired!
stop2 :  true  
Timer 2 stopped
*/

Ticker

package main

import (
   "fmt"
   "time"
)

func main() {
    
    

   ticker := time.NewTicker(500 * time.Millisecond)
   done := make(chan bool)

   go func() {
    
    
      for {
    
    
         select {
    
    
         case <-done:
            return
         case t := <-ticker.C:
            fmt.Println("Tick at ", t)
         }
      }
   }()
   time.Sleep(1500 * time.Millisecond)
   ticker.Stop()
   done <- true
   fmt.Println("Ticker stopped")
}

工作池

package main

import (
	"fmt"
	"time"
)

func work_pool(id int, worker <-chan int, result chan<- int) {
    
    
	for j := range worker {
    
    
		fmt.Println("worker ", id, " do job ", j)
		time.Sleep(500 * time.Millisecond)
		fmt.Println("worker ", id, " finished")
		result <- j + 600
	}
}

func main() {
    
    
	const mySize = 10
	workers := make(chan int, mySize)
	result := make(chan int, mySize)
	for i := 1; i <= 3; i++ {
    
    
		go work_pool(i, workers, result)
	}

	for i := 0; i < 9; i++ {
    
    
		workers <- i + 10
	}
	close(workers)
	for i := 0; i < 9; i++ {
    
    
		res := <-result
		fmt.Println("received : ", res)
	}
}

<-chan int 接收管道
chan<- int 发送管道
chan 双向管道
接收管道 只能 从管道接收值 number := <-chan
发送管道 只能 给管道发送值 chan <- number

原子计数器

package main

import (
	"fmt"
	"runtime"
	"sync"
	"sync/atomic"
)

func main() {
    
    
	runtime.GOMAXPROCS(2)
	var w sync.WaitGroup
	count := int32(0)
	w.Add(10)
	for i := 0; i < 10; i++ {
    
    
		go func() {
    
    
			for j := 0; j < 20; j++ {
    
    
				atomic.AddInt32(&count, 1)
				// count ++
			}
			w.Done()
		}()
	}
	w.Wait()
	res := atomic.LoadInt32(&count)
	fmt.Println(res)
}

若用单纯的变量, 多线程读取的 cpu cache 的值不一定对, 直接使用 count++ 可能导致输出的值错误。

猜你喜欢

转载自blog.csdn.net/weixin_43563956/article/details/126892640
今日推荐