包
Package:
- 每一组文件被称为一个包,包关键词 package,如:package net/http
- 所有的go文件都必须在第一行声明包。
- 同一个文件目录下的go文件必须声明同一个包。
- 包的名称尽量简短,保持和目录名一致,如:net/http net/cgi等。net目录下的http和cgi目录都是不同的包。
- main包,每一个go应用程序都必须有一个main包。
- main包必须都唯一的main函数作为唯一的入口。
Import
- 导入多个包用括号括起来,如:
package main
import(
_ "github.com/astaxie/beego/session/mysql"
. "github.com/smartystreets/goconvey/convey"
"net/http"
"myfmt mylib/fmt"
"fmt"
)
- 导入的多个包的时候,go会首先查找标准库中的包(/usr/local/go),其次查找GOPATH下的包。
- 包导入可以指定url(github.com/astaxie/beego/session/mysql)
- 每个包导入进来可以起个别名,在左边起个名字,如果包不用go编译的时候会报错。
- 如果包导进来不想用,只是作为初始化,比如数据库初始化,可以指定
_
符号忽略它。 - 包名字设置为.代表为本地包在调用的时候,不需要使用包名.函数调用,直接函数()调用
func main() {
//fmt.Println("hello") //用包的别名调用包的方法
Println("hello") //省略包名直接调用,点代表省略包名调用,即本地包。
}
- 每个包可以包含多个init初始化函数。init中可以做包的初始化,在main函数执行前执行。
Command
Go --help 可以看到所有的命令。
- go build 后边可以跟包名称(包名和目录名一般一样),go文件,也可以跟3个点。表示匹配所有包。
go build . //当前目录
go build github.com/astaxie/beego/session/mysql
go build github.com/astaxie/beego/... //表示匹配beego下面所有的包。
go run 运行go文件,包括编译的步骤。如:go run xxx.go
go vet可以检测代码常见的错误,但不包含复杂的逻辑错误,提交代码前执行go vet就跟php 提交前执行php -l一样是个好习惯。
gofmt 格式化代码。
godoc支持命令,http服务等查看文档,也支持把自己写的代码生成成文档包含在官方文档里(规则网上查)。go doc 和godoc是两个东西。可以执行help查看具体使用方法。
go doc fmt Print //查看fmt包print方法
godoc --http=:81//启动一个端口为81的go http服务,浏览器localhost:81访问
- go get下载包到本地。很多包需要翻墙,可以指定阿里的镜像。
GOPROXY="https://mirrors.aliyun.com/goproxy/"
go get -u github.com/astaxie/beego
- go env可以查看go的环境变量。
- go mod 管理go导入的包,go mod init 会在项目根目录下生成go.mod文件,运行程序的时候go mod会自动去查找下载需要的依赖包。
- go test 运行单元测试命令,可以go help test查看具体的用法。
go test -v ./tests -run=^TestPurpose$
指针 (指针类型,指针变量,指针地址)
go语言中的指针类型变量即拥有指针高效访问的特点,又不会发生指针偏移,从而避免了非法修改关键性数据的问题。同时,垃圾回收也比较容易对不会发生偏移的指针进行检索和回收。go的指针有2个核心的概念:
- 类型指针,允许对这个指针类型的数据进行修改,传递数据可以直接使用指针,而无须拷贝数据,类型指针不能进行偏移和运算。
- 切片,由指向起始元素的原始指针、元素数量和容量组成。
var ptr *ptr-type //ptr称为指针变量,ptr-type称为指针的类型。
var var_name var_type // var_name变量名 var_type变量类型。
ptr = &var_name //代表指针变量的值是var_name在内存中的存储地址,也就是指针变量的地址
var pptr **ptr-type //代表指向指针的指针变量,意思就是指针变量存储的是另一个指针变量的地址。
//例如:
pptr = &ptr //ptr本身存储的是var_name的地址,&ptr代表指针的地址,赋值给pptr,那么pptr存储的就是指针变量的指针地址。
举个栗子。
之前开发的时候遇到过一个问题。如下:
//获取列表
func PaperTypeList(paperTypes *[]PaperType, count *int64, limit, offset int64, name string) error {
query := getPaperQuery(name)
//countResult := query.Count(&count) //错误的地方。
countResult := query.Count(count)
if countResult.Error != nil {
if countResult.RecordNotFound() {
return &exceptions.Empty
}
return &exceptions.Persistence
}
query = getPaperQuery(name)
switch {
case limit == -1:
case limit > 0:
query = query.Limit(limit)
case limit > 100:
limit = 100
query = query.Limit(limit)
default:
limit = setup.PageSize
query = query.Limit(limit)
}
if offset > 0 {
query = query.Offset(offset)
}
result := query.Find(&paperTypes)
if result.Error != nil {
if result.RecordNotFound() {
return &exceptions.Empty
}
return &exceptions.Persistence
}
return nil
}
//调用
var (
paperTypes []models.PaperType
total int64
)
if err := models.PaperTypeList(&paperTypes, &total, limit, offset, label); err != nil {
self.Raise(err)
}
在上面错误的地方,我传了个地址进去,导致最终获取的count始终是0,单元测试过不了,debug的时候才发现count的地址发生了变化。
上面的原因就是count是个指针变量,然后query.Count(&count)
时,等于把指向指针的指针变量传过去了。