- Java锁的逻辑(结合对象头和ObjectMonitor)
- 还在用饼状图?来瞧瞧这些炫酷的百分比可视化新图形(附代码实现)⛵
- 自动注册实体类到EntityFrameworkCore上下文,并适配ABP及ABPVNext
- 基于Sklearn机器学习代码实战
go fmt
格式化 chan struct{}
来传递信号, chan bool
表达的不够清楚 30 * time.Second
比 time.Duration(30) * time.Second
更好 time.Duration
代替 int64
+ 变量名 const
声明,按逻辑和/或类型分组 var
encoding/gob
_ struct {}
字段: func
类型的空字段 http.HandlerFunc
比 http.Handler
更好 defer
到顶部 _ = b [7]
interface{}
没有任何类型约束 unsafe
包,不能保证能如期运行 panic()
go fmt
格式化 让团队一起使用官方的 Go 格式工具,不要重新发明轮子。 尝试减少代码复杂度。 这将帮助所有人使代码易于阅读.
// NOT BAD
if foo() {
// ...
} else if bar == baz {
// ...
} else {
// ...
}
// BETTER
switch {
case foo():
// ...
case bar == baz:
// ...
default:
// ...
}
chan struct{}
来传递信号, chan bool
表达的不够清楚 当你在结构中看到 chan bool 的定义时,有时不容易理解如何使用该值,例如:
type Service struct {
deleteCh chan bool // what does this bool mean?
}
但是我们可以将其改为明确的 chan struct {} 来使其更清楚:我们不在乎值(它始终是 struct {} ),我们关心可能发生的事件,例如:
type Service struct {
deleteCh chan struct{} // ok, if event than delete something.
}
30 * time.Second
比 time.Duration(30) * time.Second
更好 你不需要将无类型的常量包装成类型,编译器会找出来。 另外最好将常量移到第一位:
// BAD
delay := time.Second * 60 * 24 * 60
// VERY BAD
delay := 60 * time.Second * 60 * 24
// GOOD
delay := 24 * 60 * 60 * time.Second
time.Duration
代替 int64
+ 变量名
// BAD
var delayMillis int64 = 15000
// GOOD
var delay time.Duration = 15 * time.Second
const
声明,按逻辑和/或类型分组 var
// BAD
const (
foo = 1
bar = 2
message = "warn message"
)
// MOSTLY BAD
const foo = 1
const bar = 2
const message = "warn message"
// GOOD
const (
foo = 1
bar = 2
)
const message = "warn message"
这个模式也适用于 var .
** 每个阻塞或者 IO 函数操作应该是可取消的或者至少是可超时的 。
** 为整型常量值实现 Stringer 接口 。
** 检查 defer 中的错误 。
defer func() {
err := ocp.Close()
if err != nil {
rerr = err
}
}()
** 不要在 checkErr 函数中使用 panic() 或 os.Exit() 。
** 仅仅在很特殊情况下才使用 panic, 你必须要去处理 error 。
** 不要给枚举使用别名,因为这打破了类型安全 。
package main
type Status = int
type Format = int // remove `=` to have type safety
const A Status = 1
const B Format = 1
func main() {
println(A == B)
}
** 。
如果你想省略返回参数,你最好表示出来 。
_ = f()
比 f()
更好 ** 。
我们用 a := []T{} 来简单初始化 slice 。
** 。
用 range 循环来进行数组或 slice 的迭代 。
for _, c := range a[3:7] {...}
比 for i := 3; i < 7; i++ {...}
更好 ** 。
多行字符串用反引号(`) 。
** 。
用 _ 来跳过不用的参数 。
func f(a int, _ string) {}
time.Before
或 time.After
,不要使用 time.Sub
来获得 duration (持续时间),然后检查它的值。 ctx
,形如: func foo(ctx Context, ...)
func f(a int, b int, s string, p string)
func f(a, b int, s, p string)
** 一个 slice 的零值是 nil 。
```
var s []int
fmt.Println(s, len(s), cap(s))
if s == nil {
fmt.Println("nil!")
}
// Output:
// [] 0 0
// nil!
```
var a []string
b := []string{}
fmt.Println(reflect.DeepEqual(a, []string{}))
fmt.Println(reflect.DeepEqual(b, []string{}))
// Output:
// false
// true
** 不要将枚举类型与 < , > , <= 和 >= 进行比较 。
value := reflect.ValueOf(object)
kind := value.Kind()
if kind >= reflect.Chan && kind <= reflect.Slice {
// ...
}
** 用 %+v 来打印数据的比较全的信息 。
** 注意空结构 struct{} 。
func f1() {
var a, b struct{}
print(&a, "\n", &b, "\n") // Prints same address
fmt.Println(&a == &b) // Comparison returns false
}
func f2() {
var a, b struct{}
fmt.Printf("%p\n%p\n", &a, &b) // Again, same address
fmt.Println(&a == &b) // ...but the comparison returns true
}
** 。
errors.Wrap(err, "additional message to a given error")
** 。
在 Go 里面要小心使用 range
for i := range a
and for i, v := range &a
,都不是 a
的副本 for i, v := range a
里面的就是 a
的副本 ** 。
从 map 读取一个不存在的 key 将不会 panic 。
value := map["no_key"]
将得到一个 0 值 value, ok := map["no_key"]
更好 ** 。
不要使用原始参数进行文件操作 。
os.MkdirAll(root, 0700)
os.FileMode
** 。
不要忘记为 iota 指定一种类型 。
const (
_ = iota
testvar // testvar 将是 int 类型
)
vs 。
type myType int
const (
_ myType = iota
testvar // testvar 将是 myType 类型
)
encoding/gob
在某些时候,结构可能会改变,而你可能会错过这一点。因此,这可能会导致很难找到 bug.
// BAD
return res, json.Unmarshal(b, &res)
// GOOD
err := json.Unmarshal(b, &res)
return res, err
_ struct {}
字段:
type Point struct {
X, Y float64
_ struct{} // to prevent unkeyed literals
}
对于 Point {X:1,Y:1} 都可以,但是对于 Point {1,1} 则会出现编译错误:
./file.go:1:11: too few values in Point literal
当在你所有的结构体中添加了 _ struct{} 后,使用 go vet 命令进行检查,(原来声明的方式)就会提示没有足够的参数.
func
类型的空字段
type Point struct {
_ [0]func() // unexported, zero-width non-comparable field
X, Y float64
}
http.HandlerFunc
比 http.Handler
更好 用 http.HandlerFunc 你仅需要一个 func, http.Handler 需要一个类型.
defer
到顶部 这可以提高代码可读性并明确函数结束时调用了什么.
用 json:"id,string" 代替 。
type Request struct {
ID int64 `json:"id,string"`
}
** 以线程安全的方式创建单例(只创建一次)的最好选择是 sync.Once 。
** 永远不要使用 select{} , 省略通道, 等待信号 。
** 不要关闭一个发送(写入)管道,应该由创建者关闭 。
** math/rand 中的 func NewSource(seed int64) Source 不是并发安全的,默认的 lockedSource 是并发安全的.
** 当你需要一个自定义类型的 atomic 值时,可以使用 atomic.Value 。
** 不要省略 defer 。
** 总是关闭 http body defer r.Body.Close() 。
** 过滤但不分配新内存 。
b := a[:0]
for _, x := range a {
if f(x) {
b = append(b, x)
}
}
_ = b [7]
** time.Time 有指针字段 time.Location 并且这对 go GC 不好 。
time.Time
才(对性能)有意义,否则用 timestamp 代替 ** regexp.MustCompile 比 regexp.Compile 更好 。
func init
中初始化它 ** 请勿在你的热点代码中过度使用 fmt.Sprintf . 由于维护接口的缓冲池和动态调度,它是很昂贵的.
fmt.Sprintf("%s%s", var1, var2)
, 考虑使用简单的字符串连接。 fmt.Sprintf("%x", var)
, 考虑使用 hex.EncodeToString
or strconv.FormatInt(var, 16)
** 如果你不需要用它,可以考虑丢弃它,例如 io.Copy(ioutil.Discard, resp.Body) 。
res, _ := client.Do(req)
io.Copy(ioutil.Discard, res.Body)
defer res.Body.Close()
** 不要在循环中使用 defer,否则会导致内存泄露 。
** 不要忘记停止 ticker, 除非你需要泄露 channel 。
ticker := time.NewTicker(1 * time.Second)
defer ticker.Stop()
** 用自定义的 marshaler 去加速 marshaler 过程 。
func (entry Entry) MarshalJSON() ([]byte, error) {
buffer := bytes.NewBufferString("{")
first := true
for key, value := range entry {
jsonValue, err := json.Marshal(value)
if err != nil {
return nil, err
}
if !first {
buffer.WriteString(",")
}
first = false
buffer.WriteString(key + ":" + string(jsonValue))
}
buffer.WriteString("}")
return buffer.Bytes(), nil
}
** 。
sync.Map 不是万能的,没有很强的理由就不要使用它.
** 。
在 sync.Pool 中分配内存存储非指针数据 。
** 。
为了隐藏逃生分析的指针,你可以小心使用这个函数:
// noescape hides a pointer from escape analysis. noescape is
// the identity function but escape analysis doesn't think the
// output depends on the input. noescape is inlined and currently
// compiles down to zero instructions.
//go:nosplit
func noescape(p unsafe.Pointer) unsafe.Pointer {
x := uintptr(p)
return unsafe.Pointer(x ^ 0)
}
** 。
对于最快的原子交换,你可以使用这个 m := (*map[int]int)(atomic.LoadPointer(&ptr)) 。
** 。
如果执行许多顺序读取或写入操作,请使用缓冲 I/O 。
** 。
有 2 种方法清空一个 map:
for k := range m {
delete(m, k)
}
m = make(map[int]int)
** 用这个命令 go build -ldflags="-s -w" ... 去掉你的二进制文件 。
** 拆分构建不同版本的简单方法 。
// +build integration
并且运行他们 go test -v --tags integration .
** 最小的 Go Docker 镜像 。
CGO_ENABLED=0 go build -ldflags="-s -w" app.go && tar C app | docker import - myimage:latest
** run go format on CI and compare diff 。
** 用最新的 Go 运行 Travis-CI,用 travis 1 。
** 检查代码格式是否有错误 diff -u <(echo -n) <(gofmt -d .) 。
package_test
比 package
要好 go test -short
允许减少要运行的测试数
func TestSomething(t *testing.T) {
if testing.Short() {
t.Skip("skipping test in short mode.")
}
}
if runtime.GOARM == "arm" {
t.Skip("this doesn't work under ARM")
}
** 用 testing.AllocsPerRun 跟踪你的内存分配 。
** 多次运行你的基准测试可以避免噪音.
go test -test.bench=. -count=20
** 。
快速替换 gofmt -w -l -r "panic(err) -> log.Error(err)" . 。
** 。
go list 允许找到所有直接和传递的依赖关系 。
go list -f '{{ .Imports }}' package
go list -f '{{ .Deps }}' package
** 。
对于快速基准比较,我们有一个 benchstat 工具.
** 。
go-critic linter 从这个文件中强制执行几条建议 。
** 。
go mod why -m <module> 告诉我们为什么特定的模块在 go.mod 文件中.
** 。
GOGC=off go build ... 应该会加快构建速度 source 。
** 。
内存分析器每 512KB 记录一次分配。你能通过 GODEBUG 环境变量增加比例,来查看你的文件的更多详细信息.
** 。
go mod why -m <module> 告诉我们为什么特定的模块是在 go.mod 文件中.
go func() {
sigs := make(chan os.Signal, 1)
signal.Notify(sigs, syscall.SIGQUIT)
buf := make([]byte, 1<<20)
for {
<-sigs
stacklen := runtime.Stack(buf, true)
log.Printf("=== received SIGQUIT ===\n*** goroutine dump...\n%s\n*** end\n" , buf[:stacklen])
}
}()
** 在编译期检查接口的实现 。
var _ io.Reader = (*MyFastReader)(nil)
** len(nil) = 0 。
** 匿名结构很酷 。
var hits struct {
sync.Mutex
n int
}
hits.Lock()
hits.n++
hits.Unlock()
** 。
httputil.DumpRequest 是非常有用的东西,不要自己创建 。
** 。
获得调用堆栈,我们可以使用 runtime.Caller 。
** 。
要 marshal 任意的 JSON, 你可以 marshal 为 map[string]interface{}{} 。
** 。
配置你的 CDPATH 以便你能在任何目录执行 cd github.com/golang/go 。
bashrc
(或者其他类似的) export CDPATH=$CDPATH:$GOPATH/src
** 。
从一个 slice 生成简单的随机元素 。
[]string{"one", "two", "three"}[rand.Intn(3)]
参考资料: https://github.com/cristaloleg/go-advice/blob/master/README_ZH.md 。
最后此篇关于关于Go你不得不知道的小技巧的文章就讲到这里了,如果你想了解更多关于关于Go你不得不知道的小技巧的内容请搜索CFSDN的文章或继续浏览相关文章,希望大家以后支持我的博客! 。
关闭。这个问题是off-topic .它目前不接受答案。 想改进这个问题? Update the question所以它是on-topic对于堆栈溢出。 9年前关闭。 Improve this que
我有一堆 php 脚本计划在 CentOS 机器上的 cron 中每隔几分钟运行一次。我希望每个脚本在启动时自我检查它的前一个实例是否仍在运行,如果是则停止。 最佳答案 我这样做是为了管理任务并确保它
是否有 bash 命令、程序或 libusb 函数(尽管我没有找到)来指示 USB 设备的 OUT 或 IN 端点是什么? 例如,libusb_interface_descriptor(来自 libu
我如何知道 NSTextField 何时成为第一响应者(即当用户单击它来激活它时,但在他们开始输入之前)。我尝试了 controlTextDidBeginEditing 但直到用户键入第一个字符后才会
我怎么知道我的代码何时完成循环?完成后我还得再运行一些代码,但只有当我在那里写的所有东西都完成后它才能运行。 obj.data.forEach(function(collection) {
我正在使用音频标签,我希望它能计算播放了多少次。 我的代码是这样的: ; ; ; 然后在一个javascript文件中 Var n=0; function doing(onplaying)
我正在尝试向 Package-Explorer 的项目上下文菜单添加一个子菜单。但是,我找不到该菜单的 menuid。 所以我的问题是如何在 eclipse 中找到 menuid? 非常感谢您的帮助。
我有一个名为“下一步”的按钮,它存在于几个 asp.net 页面中。实际上它是在用户控件中。单击“下一步”时,它会调用 JavaScript 中的函数 CheckServicesAndStates。我
我正在尝试在 Visual Studio 中使用 C++ 以纳秒为单位计算耗时。我做了一些测试,结果总是以 00 结尾。这是否意味着我的处理器(Ryzen 7-1800X)不支持 ~1 纳秒的分辨率,
我有一个自定义 ListView ,其中包含一些元素和一个复选框。当我点击一个按钮时。我想知道已检查的元素的位置。下面是我的代码 public class Results extends ListAc
如何在使用 J2ME 编写的应用程序中获取网络运营商名称? 我最近正在尝试在 Nokia s40 上开发一个应用程序,它应该具有对特定网络运营商的独占访问权限。有没有这样的API或库? 最佳答案 没有
我使用服务器客户端组件,当在此组件的 TransferFile 事件中接收文件时,我使用警报消息组件。所以我希望,如果用户单击警报消息,程序将继续执行 TransferFile 事件中的代码,以在单击
如果我创建一个类A具有一些属性,例如 a, b, c我创建对象 A x1; A x2; A x3; ... A xN 。有没有办法在同一个类中创建一个方法来检索我创建的所有对象?我想创建类似 stat
我正在制作一个应用程序,其中包含相同布局的 81 个按钮。它们都被称为我创建的名为“Tile”的对象。问题是这些图 block 存储在数组中,因此我需要知道以 int 格式单击了哪个按钮才能调用图 b
UIProgressView有这个setProgress:animated: API。 有没有办法确切知道动画何时停止? 我的意思是这样的? [myProgress setProgress:0.8f
我正在使用两个 jQuery 队列,我希望其中一个队列在另一个队列完成后出队。我怎么知道第一个是否完成?我应该使用第三个队列吗?! 这是我所拥有的: var $q = $({}); $q.que
jQuery 中有没有一种方法可以知道是否至少有一个复选框已被选中? 我有一个包含很多复选框的表单,每个复选框都不同。 我需要一种 jQuery 的方式来表达这样的内容,这就是逻辑: If at le
给定 2 个选择 100 50 100 在这两种情况下,我都想在 .example 中获取数字,使用相同的选择器或者以某种方式知道 .no-text 和 之间的区别。带文字 执行
我在我的应用程序中使用 System.ComponentModel.BindingList 作为 DataGridView.DataSource。该列表非常大,需要几秒钟才能绘制到 DataGridV
我想知道用户在 Android 中选择的默认键盘。我知道我可以使用 InputMethodManager 访问已启用的输入法列表,但我想知道用户当前使用的是哪一个。 到目前为止,我已经尝试获取当前的输
我是一名优秀的程序员,十分优秀!