不务正业系列4:go语言精要

1. 安装

1.1 本体软件

在mac下,使用brew install go进行安装。另外,我们知道从 Go 1.11 版本开始,官方支持了 go module 包依赖管理工具(参见 https://www.cnblogs.com/sage-blog/p/10640947.html),并新增了 GOPROXY 环境变量,下载源代码时将会通过这个环境变量设置的代理地址,而不再是以前的直接从代码库下载。goproxy.io 这个开源项目帮我们实现好了我们想要的。该项目允许开发者一键构建自己的 GOPROXY 代理服务。同时,也提供了公用的代理服务 https://goproxy.io,我们只需设置该环境变量即可正常下载被墙的源码包了:

# 启用 Go Modules 功能
export GO111MODULE=on
# 配置 GOPROXY 环境变量
export GOPROXY=https://goproxy.io

1.2 与jupyter交互

参见 https://github.com/gopherdata/gophernotes,在mac下的安装命令为

env GO111MODULE=on go get github.com/gopherdata/gophernotes
mkdir -p ~/Library/Jupyter/kernels/gophernotes
cd ~/Library/Jupyter/kernels/gophernotes
cp "$(go env GOPATH)"/pkg/mod/github.com/gopherdata/gophernotes@v0.7.0/kernel/*  "."
chmod +w ./kernel.json # in case copied kernel.json has no write permission
sed "s|gophernotes|$(go env GOPATH)/bin/gophernotes|" < kernel.json.in > kernel.json

安装好之后,打开jupyter notebook就能看到新增了go内核啦。

1.3 编程规范

和python一样,Go是讲究书写格式的,函数的第一个{一定要和函数体在一起。有如下几个包可以控制格式

  1. 使用gofmt -w命令标准化go文件
  2. 使用golint给出修改建议
  3. 使用godoc生成文档

1.4 运行

使用go get安装github上的包。-D表示仅下载不安装。使用go install将src里面的源文件安装到$GOBIN文件夹下。
源文件使用go build编译、go run运行。也可以直接go run XX.go运行,不要太方便。

另一种方式是使用gopm。在nodejs中我们有npm,可以通过npm来下载安装一些依赖包。在go中也开发了类似的东西,那就是gopm。
使用go get -v -u github.com/gpmgo/gopm进行安装。
它不仅提供go的各种包管理,使用gopm get -g代替go get在国内还有加速效果。
注意不采用-g参数,会把依赖包下载.vendor目录下面;采用-g 参数,可以把依赖包下载到GOPATH目录中。

# 查看当前工程依赖
gopm list
# 显示依赖详细信息
gopm list -v
# 列出文件依赖
gopm list -t [file]
# 拉取依赖到缓存目录
gopm get -r xxx
# 仅下载当前指定的包
gopm get -d xxx
# 拉取依赖到$GOPATH
gopm get -g xxx
# 检查更新所有包
gopm get -u xxx
# 拉取到当前所在目录
gopm get -l xxx
# 运行当前目录程序
gopm run
# 生成当前工程的 gopmfile 文件用于包管理
gopm gen -v
# 根据当前项目 gopmfile 链接依赖并执行 go install
gopm install -v
# 更新当前依赖
gopm update -v
# 清理临时文件
gopm clean
# 编译到当前目录
gopm bin

2. 数据类型

2.1 基本类型

Go是静态语言,数据类型包括:bool,string,int,float32,float64, [](数组)。Go中的变量声明后,默认初始化为“零值”。注意不像python,字符串不能用单引号。如果用反引号`,则不需要做转义。

  • 使用reflect包查看数据类型,reflect.TypeOf()
  • 使用strconv包进行类型转换,strconv.ParseBool(), strconv.FormatBool…

2.2 数组/切片/字典

  1. 数组,固定大小,一般不用:
    var xx [2]string;xx := []int{1,2,3,4};xx := [6]int{1,2,3,4}
  2. 切片,大小只是个提示,可随时新增:
    var xx = make([]string,2)
    xx = append(xx,value)
  3. 数组和切片复制,使用:
    copy(to, from)
  4. 字典,使用make(map…),复杂数据结构都要用make关键字
    xx := make(map[string] int)
    用delete删除数组元素:
    detele(xx,key)

2.3 常量/变量,声明/赋值,作用域

用const声明常量。
定义变量的几种方式:

var s string
var s string = "hello"
var s = "hello" // 类型推断
s := "hello" // 类型推断+去掉var的简写,只能在函数内使用。

使用块表明作用域,用{}。文件本身是一个块。外部块可以访问内部块。
Go默认从package main的main函数进行。

2.4 结构体

定义:type xx struct{key1 string, key2 int}
使用:
m := xx{
key1: value1
key2: value2
}
或者
m:=xx{value1,value2}
结构体与后面的方法组合起来,可以模拟类。

3. 函数与接口

3.1 指针

和java大同小异:

  1. 使用 &变量 来获得变量的指针
  2. 使用 *数据类型 来声明指针类型
  3. 使用 *指针 来获取指针对应的变量

3.2 函数

func XX(输入 输入格式) (输出格式){
	return 输出
}

在输入框中,可以用…表示任意数量的变量

在Go中,可以将函数名放到前面作为变量:

XX:=func (输入 输入格式) (输出格式){
	return 输出
}

即可以将 func (输入 输入格式) (输出格式) 作为一种数据类型进行传输,后面加一个()就可以执行一次这个函数变量,非常像java中的内联函数。

3.3 方法

方法非常像函数,只是多了一个接收者。之所以这么定义,是为了模拟面向对象的类,使用type和方法就可以模拟类。
方法定义:func (m *Movie) summary(xx int) string{}
调用:m := Movie{…}; m.summary()

3.4 接口

接口定义:type XX interface{PowerOn() string},定义了接口名、需实现的方法等。
然后因为函数并没有implement关键字,所以实现接口的时候看不出来implement的是谁,最好加注释说明。

4. 控制语句

  1. 条件语句:if x {} else {},可以继续else if下去
  2. 循环语句1,经典for循环:for i:=0;i<10;i++{}
  3. 循环语句2,使用range,很像python中的enumerate:
numbers := []int{1,2,3,4}
for i,n := range numbers{
    fmt.Println(n)
}
  1. 没有while语句,用for代替
for {这里面的语句会不停执行,要自己加停止条件}
  1. defer:函数执行完之后会执行defer语句,在关闭网络连接、关闭文件等作业中很有用。

5. 读写/测试/日志/异常/建站

  1. 读写文件:使用io/ioutil,读出来是[]unit8,需转换成需要的形式。注意缓存读写buffer.Bytes处理字符并直接使用string的+和append方法要快(可使用benchmark测试)。
  2. json:用encoding/json包处理json字段
  3. 正则表达式:regexp包
  4. 异常处理:使用errors,其接口定义:type error interface{Error() string}。fmt.Errorf对错误做格式化输出
  5. 日志:使用log,log.Printf、log.Fatal…。一般直接打印到标准输出,然后在程序外处理。标准输入0;标准输出1;标准错误2
  6. 获取命令行参数:使用range os.Args获取所有参数;或者用flag.String(参数名,默认值,提示)定义,再使用flag.Parse()解析,使用*参数名获取值。
  7. 测试:使用testing,参考这里。几个关键点:(1) 用xx_test.go命名测试文件;(2) 引入import “testing”;(3) 测试函数以Test开头。有两类测试,t表示单元测试,b表示基准测试。使用 -bench运行基准测试,使用-cover 报告覆盖率。
  8. 建站:使用net/http包,下面是例子:
package main
import "net/http"
func hello(w http.ResponseWriter, r *http.Request){
	w.Write([]byte("Hello world"))
}
func main(){
http.HandleFunc("/",hello)
http.ListenAndServe(":8000",nil)
}

6. 并发和通道

  • 在函数前加一个go即可触发并发,一般配合通道chan一起执行。通道定义方法:c:=make(chan string)。当通道作为参数时:<-chan表明只读,chan<-表明只写,chan表明可读写
  • 通道接收消息:c <- “hello”;接收通道数据:xx := <-c,这是一个阻塞操作
  • 高级使用方法:用select case语句可以执行第一条达到的语句,执行后立即取消阻塞。使用time.After设置超时,格式为:
//select基本用法
select {
case <- chan1:
// 如果chan1成功读到数据,则进行该case处理语句
case chan2 <- 1:
// 如果成功向chan2写入数据,则进行该case处理语句
case <-time.After(5*time.Second):
// 如果上面都没有成功,则进入default处理流程。或者使用default执行默认操作

下面是例子

func showfunc(c chan string){
    t := time.NewTicker(time.Second*2)
    for {
    c <- "function finished"
    <-t.C
    }
}

func main(){
    c:=make(chan string)
    stop:=make(chan bool)
    go showfunc(c)
    go func() {time.Sleep(time.Second*4);stop <- true}() //使用内联函数
    fmt.Println("start immediately")
    for {
        select{
            case <-stop:
                return
            case msg := <-c:
            fmt.Println(msg)
        }
    }
}

main()
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值