Interface 合理性验证

在编译时验证接口的符合性。这包括:

补充:上面3条是编译器对接口的检查机制, 大体意思是错误使用接口会在编译期报错. 所以可以利用这个机制让部分问题在编译期暴露.

如果 *Handlerhttp.Handler 的接口不匹配, 那么语句 var _ http.Handler = (*Handler)(nil) 将无法编译通过.

Bad

// 如果Handler没有实现http.Handler,会在运行时报错
type Handler struct {// ...
}
func (h *Handler) ServeHTTP(w http.ResponseWriter,r *http.Request,
) {...
}

Good

type Handler struct {// ...
}
// 用于触发编译期的接口的合理性检查机制
// 如果Handler没有实现http.Handler,会在编译期报错
var _ http.Handler = (*Handler)(nil)
func (h *Handler) ServeHTTP(w http.ResponseWriter,r *http.Request,
) {// ...
}

赋值的右边应该是断言类型的零值。 对于指针类型(如 *Handler)、切片和映射,这是 nil; 对于结构类型,这是空结构。

type LogHandler struct {h   http.Handlerlog *zap.Logger
}
var _ http.Handler = LogHandler{}
func (h LogHandler) ServeHTTP(w http.ResponseWriter,r *http.Request,
) {// ...
}

Mutex 的使用方法

非导出,嵌入 mutex

type smap struct {sync.Mutex // only for unexported types(仅适用于非导出类型)data map[string]string
}func newSMap() *smap {return &smap{data: make(map[string]string),}
}func (m *smap) Get(k string) string {m.Lock()defer m.Unlock()return m.data[k]
}

对于导出的类型,使用专用字段

type SMap struct {mu sync.Mutex // 对于导出类型,请使用私有锁data map[string]string
}func NewSMap() *SMap {return &SMap{data: make(map[string]string),}
}func (m *SMap) Get(k string) string {m.mu.Lock()defer m.mu.Unlock()return m.data[k]
}

在危险的边缘拷贝在 Slices 和 Maps

slices 和 maps 包含了指向底层数据的指针,因此在需要复制它们时要特别注意。

接收 Slices 和 Maps

Bad

func (d *Driver) SetTrips(trips []Trip) {d.trips = trips
}trips := ...
d1.SetTrips(trips)// 你是要修改 d1.trips 吗?
trips[0] = ...

Good

func (d *Driver) SetTrips(trips []Trip) {d.trips = make([]Trip, len(trips))copy(d.trips, trips)
}trips := ...
d1.SetTrips(trips)// 这里我们修改 trips[0],但不会影响到 d1.trips
trips[0] = ...

返回 slices 或 maps

Bad

type Stats struct {mu sync.Mutexcounters map[string]int
}// Snapshot 返回当前状态。
func (s *Stats) Snapshot() map[string]int {s.mu.Lock()defer s.mu.Unlock()return s.counters
}// snapshot 不再受互斥锁保护
// 因此对 snapshot 的任何访问都将受到数据竞争的影响
// 影响 stats.counters
snapshot := stats.Snapshot()

Good

type Stats struct {mu sync.Mutexcounters map[string]int
}func (s *Stats) Snapshot() map[string]int {s.mu.Lock()defer s.mu.Unlock()result := make(map[string]int, len(s.counters))for k, v := range s.counters {result[k] = v}return result
}// snapshot 现在是一个拷贝
snapshot := stats.Snapshot()

慎重创建 size > 1 的 Channel

默认情况下,channel 是无缓冲的,其 size 为 0。

channel 通常 size 应为 1 或是 0。

Bad

// 不推荐
c := make(chan int, 64)

一般来说,不推荐创建 size > 1 的 Channel。

当需要创建 size > 1 的 Channel ****时,需要考虑:

是什么阻止了 channel 在高负载下和阻塞写时的写入,以及当这种情况发生时系统逻辑有哪些变化

Good

// 大小:1
c := make(chan int, 1) // 或者
// 无缓冲 channel,大小为 0
c := make(chan int)

避免在公共结构中使用类型嵌入

Go 允许 类型嵌入 作为继承和组合之间的折衷。

外部类型获取嵌入类型的方法的隐式副本、获得与类型同名的字段。

如果嵌入的类型是 public,那么外部类型获得的字段也是 public。为了保持向后兼容性,外部类型的每个未来版本都必须保留嵌入类型。

无论是使用嵌入式结构还是使用嵌入式接口,嵌入式类型都会限制类型的演化:

Bad

// ConcreteList 是一个实体列表。
type ConcreteList struct {*AbstractList
}
// AbstractList 是各种实体列表的通用实现。
type AbstractList interface {Add(Entity)Remove(Entity)
}
// ConcreteList 是一个实体列表。
type ConcreteList struct {AbstractList
}

Good

// ConcreteList 是一个实体列表。
type ConcreteList struct {list AbstractList
}
// 添加将实体添加到列表中。
func (l *ConcreteList) Add(e Entity) {l.list.Add(e)
}
// 移除从列表中移除实体。
func (l *ConcreteList) Remove(e Entity) {l.list.Remove(e)
}

业务中很少需要嵌入类型。 这是一种方便,可以避免编写冗长的委托方法。

尽管编写这些委托方法是乏味的,但是额外的工作隐藏了实现细节,留下了更多的更改机会,还消除了在文档中发现完整列表接口的间接性操作。

使用 init() 时的注意事项

虽然init()顺序是明确的,但代码可以更改, 因此init()函数之间的关系可能会使代码变得脆弱和容易出错。

应避免因依赖于其他init()函数顺序而造成的问题。

同时应该避免一些动态操作,以免在如go test 之类的环境造成不必要的动态操作:

但在某些情况下,init()可能更可取或是必要的,可能包括:

Uber 《Go语言编程规范》学习笔记(一)相关推荐

  1. C语言编程规范 学习笔记

    C语言编程规范 一.代码总体原则 1.清晰 2.简洁 3.选择适合的风格,与代码原有风格保持一致 二.头文件 背景 术语定义 原则 2.1 头文件中适合放置接口的声明,不适合放置实现 原则 2.2 头 ...

  2. C语言编程规范学习笔记和总结(附华为编程规范机试参考试题)

    目录 规范说明 一.头文件 原则1.1 头文件中适合放置接口的声明,不适合放置实现. 原则1.2 头文件应当职责单一 原则1.3 头文件应向稳定的方向包含 规则1.1 每一个.c文件应有一个同名.h文 ...

  3. Uber Go 语言编程规范

    相信很多人前两天都看到 Uber 在 github 上面开源的 Go 语言编程规范了,原文在这里:https://github.com/uber-go/guide/blob/master/style. ...

  4. 《华为C语言编程规范 》笔记

    title: <华为C语言编程规范 > data: 2021-11-7 第一章 排版 相对独立的程序块之间.变量说明之后必须加空行. if.for.do.while.case.switch ...

  5. 华为C语言编程规范重点笔记(学习C编程规范看这篇就够了)

    华为C编程规范原文详情:link. 一.代码总体原则 1.清晰第一 **清晰性是易于维护.易于重构的程序必需具备的特征.**"程序必须为阅读它的人而编写,只是顺便用于机器执行".& ...

  6. “华为云企业级Java编程规范”学习笔记

    一."Java基础语句"编程规范 Switch 语句要有defualt分支,除非Swich的条件变量是枚举类型; 多条件分支语句最后应包含一个else分支; 二."类的使 ...

  7. 《Go语言编程》学习笔记 (二)

    2019独角兽企业重金招聘Python工程师标准>>> 第2章 顺序编程 2.1 变量     2.1.1 变量声明 关键字var,类型信息放在变量名之后 var v1 int va ...

  8. Uber Go 语言编程规范:使用 go.uber.org/atomic

    通过sync/atomic 包的原子操作对原始类型s(int32, int64, etc.) 进行操作的时候,很容易忘记在对变量进行读取和修改的时候,使用原子操作. 而go.uber.org/atom ...

  9. Uber Go 语言编程规范:避免语义不明确的参数(Naked Parameters)

    函数调用中的意义不明确的参数(Naked parameters )可能会影响可读性,当参数名称的含义不明显时,请为参数添加 C 样式注释 (/* ... */) Bad // func printIn ...

  10. 【读书笔记】-《华为-C语言编程规范》

    前言 作为程序开发者,避免不了阅读别人代码,那么就会涉及到到一门语言的编程规范.规范虽然不是语言本身的硬性要求,但是已经是每一个语言使用者约定俗成的一个规范.按照编程规范编写的代码,至少在代码阅读时, ...

最新文章

  1. VC++实现QQ聊天工具【源代码】
  2. Android开发之自定义Notification(源代码分享)
  3. IOS 学习资料汇总(^_^)
  4. 基于Solr的空间搜索学习笔记
  5. linux的三大服务器,Linux三大重要事件
  6. alert 乱码(转 学习)
  7. fast角点检测 java_opencv3_java 图像的角点检测DetectConers goodFeaturesToTrack
  8. java中vector,array,list,arraylist的区别
  9. Make.am中生成.la动态库的同时要链接.a静态库的问题
  10. JUC 常用 4 大并发工具类:CountDownLatch、CyclicBarrier、Semaphore、Exchanger
  11. odbc连接远程服务器,使用odbc连接数据库
  12. 如何在Linux里面安装Java的运行环境(详细过程)
  13. ASP.NET程序读取二代身份证(附源码)
  14. 使用pynput监听键盘组合键
  15. 【JY】流体力学之牛顿流体和非牛顿流体
  16. 达梦数据库初始化、创建用户和修改密码
  17. 二分法求三次方根代码
  18. tmall.item.simpleschema.add( 天猫简化发布商品 )
  19. 解决微信浏览器video标签自动播放视频失效
  20. 【Windows 问题系列第 2 篇】如何让显示的窗口在桌面的最上面,而不被其它窗口遮挡?

热门文章

  1. 十月一“闭关修炼”,读完这些Java技术栈,愿金九银十过五斩六
  2. java apache类库_java-类库-Apache Commons补充
  3. Visual Studio Code中比较不同的分支(How to compare different branches in Visual Studio Code)
  4. 服务器nvme硬盘识别不了,NVMe硬盘无法安装win7怎么办|安装win7找不到nvme硬盘解决方法...
  5. ARM芯片内部堆栈的理解及MAP文件的查看
  6. 什么是业务流程重组?
  7. 「Prompt」是什么,并用简单的范例让你了解如何善用他、避开陷阱,以此获得更好的 ChatGPT 回复。
  8. html5+JS制作音乐播放器
  9. 一、基础入门下------------视频处理
  10. mysql vsize_Oracle 中的Userenv()