go语言编程系列(二)

简介: go语言编程系列(二)

Golang的命名规范

1、命名在所有的编程语言中都是有规范的,也是需要遵守的,只有我们有了好的命名习惯才可以写出好的代码。例如我们在生活中对建筑的命名也是希望可以表达这个建筑的含义和作用。

2、在Go语言中也是一样的,Go语言的函数名,变量名,常量名,类型名和包的命名都是遵守这一规则的:一个一个名字必须以一个字母或下划线开头,后面可以跟任意数量的字母,数字或者下划线。

3、大写和小写字母是不同的,Car和car是两个不同的名字。

4、Go语言中也有类似java的关键字,且关键字不能自定义名字,只能在特定语法结构中使用。


break default func interface selectcase defer go map structchan else goto package switchconst fallthrough if range typecontinue for import return var

5、除此之外Go语言中还有30多个预定义的名字,比如int和true等


内建常量: true false iota nil内建类型: int int8 int16 int32 int64 uint uint8 uint16 uint32uint64 uintptrfloat32 float64 complex128 complex64 bool byte runestring error内建函数: make len cap new append copy close delete complexreal imag panic recover

6、通常我们在Go语言编程中推荐命名方式是驼峰命名例如:ReadAll,不推荐下划线命名。

7、下面总结了平时项目中必须遵守的规范:

Import规范

①、原则上遵守go imports 规范,go imports会自动把依赖按首字母排序,并对包进行分组管理,通过空行隔开,默认分为本地包(标准库,内部包),第三方包。

②、标准包永远位于最上面的第一组。

③、使用完整路径,不要使用相对路径。

④、包名和git路径不一致时,或者多个相同包名冲突时,使用别名代替。

错误处理

①、error作为函数的值返回,必须对error进行处理,或者返回值赋值给明确忽略。

②、error作为函数值返回且有多个返回值的时候,error必须是最后一个参数。


// 不建议func do() (error, int) {}// 建议func do() (int, error) {}

③、优先处理错误,能return尽早return,理想情况代码逻辑是平铺顺着读就能看得懂,过多的嵌套会降低可读性。

④、错误返回优先独立判断,不与其他变量组合判断


// 不建议x, y, err := f()if err != nil || y == nil {return err // 当y与err都为空时,函数的调用者会出现错误的调用逻辑}// 建议x, y, err := f()if err != nil {return err}if y == nil {return fmt.Errorf("some error")}

panic

①、在业务逻辑处理中禁止使用panic


②、在main包中只有当完全不可运行的情况可使用panic,例如:文件无法打开,数据库无法连接导致程序无法正常运行。

③、对于其他的包,可导出的接口不能有panic,只能在包内使用

④、建议在main包中使用log.Fatal来记录错误,这样就可以由log来结束程序,或者将panic抛出的异常记录到日志文件中,方便排查问题。

⑤、panic捕获只能到goroutine最顶层,每个自行启动的groutine,必须在入口处捕获panic,并打印详细堆栈信息或进行其他处理。

recover

①、recover用于捕获runtime的异常,禁止滥用recover。

②、必须在defer中使用,一般用来捕获程序运行期间发生异常抛出的panic或程序主动抛出的panic。

单元测试

①、单元测试文件名命名规范为example_test.go

②、测试用例的函数名称必须以Test开头,例如TestExample

③、如果存在func Foo,单测函数可以带下划线,为func Test_Foo,如果存在func(b*Bar)Foo,单测函数可以为func TestBar_Foo,下划线不能出现在前面描述情况以外的位置。

④、每个重要的可导出函数都要首先编写测试用例,测试用例和正规代码一起提交方便回归测试。

类型断言失败处理

type assertion的单个返回值形式针对不正确的类型将产生panic。因此,请始终使用"comma ok"的惯用法


var i interface{}// 不建议t := i.(string)

i.(string) 将i或至少尝试将i(type interface{})强制转换为type string。

尝试是因为说i是int,强制转换为type string会panic恐慌。

如果这听起来不太好,则可以将语法更改为


x,ok:=i.(string)

在这种情况下,如果i不是string,则代码ok为false,而代码不会panic恐慌。


// 建议t, ok := i.(string)if !ok {// 优雅地处理错误}

注释:

①、在编码阶段同步写好变量,函数,包注释,注释可以通过godoc导出生成文档。

②、程序中每个被导出(大写的)名字,都应该有一个文档注释

③、所有注释掉的代码在提交code review前都应该被删除掉,除非添加注释讲解为什么删除,并且标明后续处理建议(比如删除计划).

命名规范:

①、文件名应该采用小写,并且使用下划线分割各个单词,文件名尽量采用有意义简短的。

②、结构体,接口,变量,常量,函数均采用驼峰命名。

Golang语言从语法层面进行了以下限定:任何需要对外暴漏的名字必须以大写字母开头,不需要对外暴漏的则以小写字母开头。

当一个命名以一个大写字母开头,如GetUserName,那么使用这种形式的标识符的对象就可以被外部包的代码使用(客户端程序需要先导入这个包),这称为导出(如面向对象语言中的public);命名如果以小写字母开头,则对包外是不可兼得,但是他们在整个包的内部是可见的并且可用的(如面向对象语言中的private)。

举个例子,假设我们有一个包叫做example,其中定义了一个变量"Name":


package examplevar Name string = "hello"

由于变量"Name"的首字母是大写,所以它是可以导出的,可以被其他的包导入后直接使用:


package mainimport (  "fmt"  "example")func main() {  fmt.Println(example.Name) // 输出:hello}

但是如果把"Name"的首字母改为小写,那么它就是不可导出的,外部包是无法访问和使用它:


package example  var name string = "hello"package mainimport (  "fmt"  "example")func main() {  fmt.Println(example.name) // 编译错误:name undefined (cannot refer to  unexported name example.name)}

因此,在Golang中,通过标识符的命名规范则来实现访问控制,可以有效地保障代码的封装性和安全性。

方法命名:

Golang中的方法命名遵循一般的命名规则,遵守首字母大小访问控制规则,同时,也建议采用驼峰命名法。

在Golang中,方法通常是与某个类型(结构体,接口等)关联的函数,方法名应该简洁明了,描述清楚该方法的作用和功能,通常使用动词加上一定的描述或说明来命名。

以下是一些常见的方法命名规范:

①、GetXxx:表示获取某个属性的值,例如GetName:表示获取年龄

②、SetXxx:表示设置某个属性的值,例如SetAge:表示设置年龄

③、AddXxx:表示添加某个元素或者对象,例如AddItem:表示添加一个元素

④、DoXxx:表示执行某个动作,例如DoSomething表示执行某个操作

⑤、XxxWithYyy:表示使用Yyy作为参数执行Xxx操作,例如WriteWithTimout表示使用超时参数执行写操作

需要注意的是,方法名应该尽量使用缩写或缩略语,除非是广泛使用常见的缩写,否则容易引起歧义和误解,同时,方法名应该尽量避免冗长,以保持代码的简洁性和可读性。

例如:假设我们有一个结构体叫做"Person",它有一个方法"SayHello"


type Person struct {   Name string   Age int}func (p *Person) SayHello() {   fmt.Printf("Hello, my name is %s and I am %d years old.\n", p.Name,   p.Age)}

在上面的例子中,我们使用了驼峰式命名方法来命名方法“SayHello”,同时结合动词和名词来描述该方法的作用,这样做可以使代码更易懂,易读。

变量命名:

和结构体类似,一般遵守驼峰命名法,首字母根据访问控制大小写,但遇到特有名词时,需要遵守以下规则:

如果变量为私有,且特有名词为首个单词,则使用小写,如appService;

若变量为bool类型,则名称应以has,is,can或allow开头。


var isExist boolvar hasConflict boolvar canManage boolvar allowGitHook bool

常量命名:

常量需要使用全部大写字母组成,并使用下划线分词


const APP_URL = "https://www.baidu.com"

如果是枚举类型的常量,需要先创建对应的类型


type Scheme stringconst{   HTTP Scheme = "http"   HTTPS Scheme = "https"}

控制语句

①、if语句


// 不建议,变量优先在左if nil != err {}// 建议这种if err != nil {}// 不建议,bool类型变量直接进行if has == true {}// 建议if has {}

①、switch语句,必须要有default哪怕什么都不做

②、业务代码禁止使用goto,其他框架或底层源码推荐尽量不用。

Defer

①、当存在资源管理时,应紧跟defer函数进行资源的释放

②、判断是否有错误发生之后,再defer释放资源


resp, err := http.Get(url)if err != nil {return err}// defer 放到错误处理之后,不然可能导致panicdefer resp.Body.Close()

③、禁止在循环中的延迟函数中使用defer,因为defer的执行需要外层函数的结束后才会释放,未来会有很多坑


// 不要这样使用func filterSomething(values []string) {  for _, v := range values {  fields, err := db.Query(xxx)  if err != nil {}defer fields.Close()// xxx }}// 但是可以使用这种方式func filterSomething(values []string) {  for _, v := range values {  func() {  fields, err := db.Query(xxx)  if err != nil {  // xxx  }defer fields.Close()  //x xxx  }() }}

魔法数字:

如果魔法数字出现超过2次,则禁止使用


func getArea(r float64) float64 {  return 3.14 * r * r}func getLength(r float64) float64 {  return 3.14 * 2 * r}// 建议定义一个常量代替魔法数字// PI xxxconst PI = 3.14

代码规范性常用工具:

上面提到的很多规范,go语言本身在代码规范性这方面做了很多的努力,很多限制都是强制性语法要求,例如左大括号不换行,引用的包或者定义的变量不使用会报错,此外go还是提供了很多好用的工具帮助我们进行代码规范:

①、gofmt

大部分的格式问题可以通过gofmt解决,gofmt自动格式化代码,保证所有的go代码与官方推荐的格式保持一致,于是所有格式有关的问题,都以gofmt的结果为准。

②、goimport

我们强烈建议使用goimport,该工具在gofmt的基础上增加了自动删除和引入包


go get golang.org/x/tools/cmd/goimports

③、go vet

vet工具可以帮助我们静态分析我们的源码存在的各种问题,例如多余的代码,提前return的逻辑,struct的tag是否符合标准等


go get golang.org/x/tools/cmd/vet
相关文章
|
2月前
|
存储 安全 Java
【Golang】(4)Go里面的指针如何?函数与方法怎么不一样?带你了解Go不同于其他高级语言的语法
结构体可以存储一组不同类型的数据,是一种符合类型。Go抛弃了类与继承,同时也抛弃了构造方法,刻意弱化了面向对象的功能,Go并非是一个传统OOP的语言,但是Go依旧有着OOP的影子,通过结构体和方法也可以模拟出一个类。
201 1
|
10月前
|
编译器 Go
揭秘 Go 语言中空结构体的强大用法
Go 语言中的空结构体 `struct{}` 不包含任何字段,不占用内存空间。它在实际编程中有多种典型用法:1) 结合 map 实现集合(set)类型;2) 与 channel 搭配用于信号通知;3) 申请超大容量的 Slice 和 Array 以节省内存;4) 作为接口实现时明确表示不关注值。此外,需要注意的是,空结构体作为字段时可能会因内存对齐原因占用额外空间。建议将空结构体放在外层结构体的第一个字段以优化内存使用。
|
10月前
|
运维 监控 算法
监控局域网其他电脑:Go 语言迪杰斯特拉算法的高效应用
在信息化时代,监控局域网成为网络管理与安全防护的关键需求。本文探讨了迪杰斯特拉(Dijkstra)算法在监控局域网中的应用,通过计算最短路径优化数据传输和故障检测。文中提供了使用Go语言实现的代码例程,展示了如何高效地进行网络监控,确保局域网的稳定运行和数据安全。迪杰斯特拉算法能减少传输延迟和带宽消耗,及时发现并处理网络故障,适用于复杂网络环境下的管理和维护。
|
4月前
|
Cloud Native 安全 Java
Go:为云原生而生的高效语言
Go:为云原生而生的高效语言
297 1
|
4月前
|
Cloud Native Go API
Go:为云原生而生的高效语言
Go:为云原生而生的高效语言
397 0
|
4月前
|
Cloud Native Java Go
Go:为云原生而生的高效语言
Go:为云原生而生的高效语言
260 0
|
4月前
|
Cloud Native Java 中间件
Go:为云原生而生的高效语言
Go:为云原生而生的高效语言
230 0
|
4月前
|
Cloud Native Java Go
Go:为云原生而生的高效语言
Go:为云原生而生的高效语言
332 0
|
4月前
|
数据采集 Go API
Go语言实战案例:多协程并发下载网页内容
本文是《Go语言100个实战案例 · 网络与并发篇》第6篇,讲解如何使用 Goroutine 和 Channel 实现多协程并发抓取网页内容,提升网络请求效率。通过实战掌握高并发编程技巧,构建爬虫、内容聚合器等工具,涵盖 WaitGroup、超时控制、错误处理等核心知识点。
|
4月前
|
数据采集 JSON Go
Go语言实战案例:实现HTTP客户端请求并解析响应
本文是 Go 网络与并发实战系列的第 2 篇,详细介绍如何使用 Go 构建 HTTP 客户端,涵盖请求发送、响应解析、错误处理、Header 与 Body 提取等流程,并通过实战代码演示如何并发请求多个 URL,适合希望掌握 Go 网络编程基础的开发者。