查看文档
go doc time
go doc hello.HelloReply
stringer
自动将常量转换成相应的字符串
原理
将相关的常量转换为 同一种类型
并给这个类型加上 String() 函数, 这样调用 fmt.Print 之类的函数就会 自动调用 String() 转换成相应的字符串了
有了 go mod 和 proxy 再也不用墙了
go get -u golang.org/x/tools/cmd/stringer
示例
main.go
//go:generate stringer -type=CID
package main
import "fmt"
//go:generate stringer -type=CID
// 注意//与go:generate字符之间不能有空格
type CID byte
const (
LinkCheckReq CID = 0x02
LinkCheckAns CID = 0x03
LinkADRReq CID = 0x04
LinkADRAns CID = 0x05
)
func main() {
fmt.Println(LinkADRAns)
}
$ go generate
这样在同目录下会生成 cid_string.go
~/gol $ go run main.go cid_string.go
LinkADRAns
性能分析
https://github.com/caibirdme/hand-to-hand-optimize-go
package main
import (
"fmt"
"log"
"net/http"
"github.com/feixiao/httpprof"
"github.com/julienschmidt/httprouter"
)
func main() {
router := httprouter.New()
log.Fatal(http.ListenAndServe(":8080", httpprof.WrapRouter(router)))
}
http://localhost:8080/debug/pprof/ 就可以访问 分析项目
once
func demo1() {
var once sync.Once
var wg sync.WaitGroup
say := func() { fmt.Println("hello") }
// 无论你折腾几回 once 变量确保了 say 只被调用一回
wg.Add(2)
go func(o *sync.Once) { o.Do(say); wg.Done() } (&once)
go func() { once.Do(say); wg.Done() } ()
once.Do(say)
wg.Wait()
}
同步
startChan := make(chan bool)
go somefunc(startChan)
<-startChan
func somefunc(start chan) {
... 干你想干的事 ...
// 通知 调用方, 我已经启动好了
close(start)
...
}
for select 内部的 continue 和 break
// for select 内部的 continue 和 break
func demo5Worker(wg *sync.WaitGroup, c1 chan bool, c2 chan bool) {
defer wg.Done()
var done bool
for {
select {
case <- c1:
fmt.Println("recived c1")
continue // select 内部没有 continue, continue 是跳到了 for 的下一次循环
// 将不会到达 fmt.Println("work after select") 那一行
case <- c2:
fmt.Println("recived c2")
done = true
// select 内部有 break
break // 这个break 仅仅跳出了 select
// 接下去就到了 fmt.Println("work after select") 那一行
// 想跳出 for 中的 select 你得 goto return 或者 像我例子一样搞个变量
}
fmt.Println("work after select")
if done {
break
}
}
}
正则 regexp
https://blog.csdn.net/tennysonsky/article/details/79081524
defer 是以函数为范围的
{} 结束时 是不会调用的
sync.Pool
是减少垃圾回收次数的,不是保存数据的
select 和c语言不同 不 roll down
default 当 case 们都不能马上执行的时候调用
channel 多个goroutine 同时等待 channel, 等到的goroutine是随机的,
不是先等就可以先获得
执行程序 获取输出
b, err := exec.Command("uname", "-a").Output()
AutoGOMAXPROCS()
附带 调用堆栈, 到 codis 代码里抄的
func TraceN(skip, depth int) Stack {
s := make([]*Record, 0, depth)
for i := 0; i < depth; i++ {
r := Caller(skip + i + 1)
if r == nil {
break
}
s = append(s, r)
}
return s
}
func Caller(skip int) *Record {
pc, file, line, ok := runtime.Caller(skip + 1)
if !ok {
return nil
}
fn := runtime.FuncForPC(pc)
if fn == nil || strings.HasPrefix(fn.Name(), "runtime.") {
return nil
}
return &Record{
Name: fn.Name(),
File: file,
Line: line,
}
}
debug
go get github.com/go-delve/delve/cmd/dlv
help 查看 所有命令
dlv debug ./main.go
b main.main
c 运行到断点
b /home/goworkspace/src/github.com/mytest/main.go:20
调试已经运行的程序
dlv attach pid
要把 ptrace_scope 的值设置为0
第一次运行的时候要先 c-f c-x 下
(op "/sudo:localhost:/proc/sys/kernel/yama/ptrace_scope")
go plugin
用go生成go的动态库 c语言的动态库 给别的程序调用等等
http://www.361way.com/go-plugin/5925.html
string []byte 相互转换
[]byte("hello")
string([]byte{99,98,97}) // cba
func Slice(s string) (b []byte) {
pb := (*reflect.SliceHeader)(unsafe.Pointer(&b))
ps := (*reflect.StringHeader)(unsafe.Pointer(&s))
pb.Data, pb.Len, pb.Cap = ps.Data, ps.Len, ps.Len
return
}
func String(b []byte) string {
// strings.Builder String() 的源码
return *(*string)(unsafe.Pointer(&b))
}