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
相关文章
|
16天前
|
存储 Go 索引
go语言中数组和切片
go语言中数组和切片
26 7
|
15天前
|
Go 开发工具
百炼-千问模型通过openai接口构建assistant 等 go语言
由于阿里百炼平台通义千问大模型没有完善的go语言兼容openapi示例,并且官方答复assistant是不兼容openapi sdk的。 实际使用中发现是能够支持的,所以自己写了一个demo test示例,给大家做一个参考。
|
16天前
|
程序员 Go
go语言中结构体(Struct)
go语言中结构体(Struct)
92 71
|
15天前
|
存储 Go 索引
go语言中的数组(Array)
go语言中的数组(Array)
100 67
|
18天前
|
Go 索引
go语言for遍历数组或切片
go语言for遍历数组或切片
88 62
|
20天前
|
并行计算 安全 Go
Go语言中的并发编程:掌握goroutines和channels####
本文深入探讨了Go语言中并发编程的核心概念——goroutine和channel。不同于传统的线程模型,Go通过轻量级的goroutine和通信机制channel,实现了高效的并发处理。我们将从基础概念开始,逐步深入到实际应用案例,揭示如何在Go语言中优雅地实现并发控制和数据同步。 ####
|
16天前
|
存储 Go
go语言中映射
go语言中映射
32 11
|
18天前
|
Go
go语言for遍历映射(map)
go语言for遍历映射(map)
29 12
|
17天前
|
Go 索引
go语言使用索引遍历
go语言使用索引遍历
26 9
|
21天前
|
安全 Serverless Go
Go语言中的并发编程:深入理解与实践####
本文旨在为读者提供一个关于Go语言并发编程的全面指南。我们将从并发的基本概念讲起,逐步深入到Go语言特有的goroutine和channel机制,探讨它们如何简化多线程编程的复杂性。通过实例演示和代码分析,本文将揭示Go语言在处理并发任务时的优势,以及如何在实际项目中高效利用这些特性来提升性能和响应速度。无论你是Go语言的初学者还是有一定经验的开发者,本文都将为你提供有价值的见解和实用的技巧。 ####