|
|
## 目录
|
|
|
* [代码声明](#代码声明)
|
|
|
* [命名规范](#命名规范)
|
|
|
* [项目约定](#项目约定)
|
|
|
* [注意事项](#注意事项)
|
|
|
|
|
|
### 代码声明
|
|
|
|
|
|
#### 命名规范
|
|
|
|
|
|
1.包名
|
|
|
|
|
|
```
|
|
|
*
|
|
|
package名和目录保持一致,需避免和标准库冲突
|
|
|
小写
|
|
|
*
|
|
|
package comm
|
|
|
```
|
|
|
|
|
|
2.命名
|
|
|
|
|
|
```
|
|
|
package pkg
|
|
|
|
|
|
*1.错误*
|
|
|
/*
|
|
|
定义在包的首部,所有错误都定义在一起,
|
|
|
并且以Err开头
|
|
|
*/
|
|
|
var ErrFooBar = fmt.Errorf("pkg: ...")
|
|
|
|
|
|
*2.变量*
|
|
|
/*
|
|
|
采用驼峰命名
|
|
|
*/
|
|
|
var fooBar int
|
|
|
|
|
|
*3.常量*
|
|
|
/*
|
|
|
大写+下划线
|
|
|
*/
|
|
|
var(
|
|
|
FOO = 1
|
|
|
BAR = 2
|
|
|
FOO_BAR = 3
|
|
|
)
|
|
|
|
|
|
*4.结构*
|
|
|
/*
|
|
|
采用驼峰命名法
|
|
|
*/
|
|
|
type FooBar struct{
|
|
|
foo int
|
|
|
Bar string
|
|
|
}
|
|
|
|
|
|
|
|
|
*5.方法接口*
|
|
|
/*
|
|
|
采用驼峰命名法
|
|
|
非对外方法,首字母需为小写
|
|
|
*/
|
|
|
func foo(){}
|
|
|
func Foo(){}
|
|
|
```
|
|
|
|
|
|
3.目录结构
|
|
|
```
|
|
|
* conf //配置
|
|
|
* dev.conf
|
|
|
* prod.conf
|
|
|
* controller //控制器
|
|
|
* v1
|
|
|
* auth.go
|
|
|
* internal
|
|
|
* repository //存储层
|
|
|
* user.go
|
|
|
* *_mock.go
|
|
|
* model //模型
|
|
|
* protocol //协议层
|
|
|
* routers //路由
|
|
|
* service //逻辑层
|
|
|
* auth
|
|
|
* static //静态数据
|
|
|
* views //视图
|
|
|
|
|
|
* main.go
|
|
|
* Dockerfile
|
|
|
* README.md
|
|
|
* *.sh //脚本
|
|
|
```
|
|
|
|
|
|
#### 项目约定
|
|
|
|
|
|
1. 入参跟返回值都要定义一个协议结构 protocol.XxxRequest *protocol.XxxResponse,方便扩展
|
|
|
2. 函数方法的变量都定义在函数的头几行 var( ... )
|
|
|
3. 服务调用尽量封装成接口,方便测试扩展 比如:ISmsServe{ Send() error }
|
|
|
4. 公用的基础代码库,需要做一下封装放在 [gocomm](http://gitlab.fjmaimaimai.com/mmm-go/gocomm) ,方便在其他项目中调用
|
|
|
4. 可以使用代码生成固定格式, [项目地址](http://gitlab.fjmaimaimai.com/mmm-go/gencode) 脚本:.\gencode.exe new -c Auth -m Login
|
|
|
|
|
|
```
|
|
|
package pkg
|
|
|
//Login
|
|
|
func(this *AuthController)Login(){
|
|
|
var msg *mybeego.Message
|
|
|
defer func(){
|
|
|
this.Resp(msg)
|
|
|
}()
|
|
|
var request *protocol.LoginRequest
|
|
|
if err:=json.Unmarshal(this.ByteBody,&request);err!=nil{
|
|
|
log.Error(err)
|
|
|
msg = mybeego.NewMessage(1)
|
|
|
return
|
|
|
}
|
|
|
if b,m :=this.Valid(request);!b{
|
|
|
msg = m
|
|
|
return
|
|
|
}
|
|
|
msg = this.GenMessage(auth.Login(request))
|
|
|
}
|
|
|
|
|
|
/*Login */
|
|
|
type LoginRequest struct {
|
|
|
Xxx string`json:"xxx" valid:"Required"`
|
|
|
}
|
|
|
type LoginResponse struct {
|
|
|
}
|
|
|
|
|
|
func Login(request *protocol.LoginRequest)(rsp *protocol.LoginResponse,err error){
|
|
|
var (
|
|
|
|
|
|
)
|
|
|
rsp =&protocol.LoginResponse{}
|
|
|
return
|
|
|
}
|
|
|
```
|
|
|
|
|
|
|
|
|
#### 注意事项
|
|
|
|
|
|
1. 启动一个groutine(eg:go func(){}()),需要在函数内进行recover,不然groutine里面panic,会导致外部程序一起崩溃掉;
|
|
|
2. 当接受者是map, chan, func, 不要使用指针传递,因为它们本身就是引用类型
|
|
|
3. 当接受者类型是一个结构体并且很庞大,或者是一个大数组,建议使用指针传递来提高性能,其他场景使用值传递即可
|
|
|
4. 当接受者是一个结构体,并且包含了sync.Mutex或者类似的用于同步的成员。必须使用指针传递,避免成员拷贝
|
|
|
5. 当函数内部需要修改接受者,必须使用指针传递
|
|
|
6. 声明空的slice应该使用下面的格式: var t []string 不要使用 t := []string{} ,前者声明了一个nil slice而后者是一个长度为0的非nil的slice。
|
|
|
|
...
|
...
|
|