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++ 可能导致输出的值错误。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值