代码和理解
结构体
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++
可能导致输出的值错误。