long blogs

进一步有进一步惊喜


  • Home
  • Archive
  • Tags
  •  

© 2025 long

Theme Typography by Makito

Proudly published with Hexo

go笔记(一)

Posted at 2020-05-17 笔记 go 

go安装

在https://golang.google.cn/dl/下载对应的版本之后解压要想要的文件夹
配置环境变量:

  • GOROOT: go编译器所在的文件夹
  • GOPATH: go三方src所在的文件夹,如果不用go mod的话,所有的项目都要在GOPATH的src目录下编程.
  • GOPROXY: go的代理,国内一般设置为https://goproxy.io,direct"
    将GOPATH的bin文件夹加入PATH环境,以便于能够通过命令行访问。
    linux:的profile文件配置如下
1
2
3
4
5
# golang
export GOROOT=/work/soft/go
export GOPATH=/work/soft/dev/gopath
export GOPROXY=https://goproxy.io,direct
export PATH=$PATH:$GOROOT/bin

Windows配置类似。

go get 无法使用问题解决办法

使用第三方包gopm
设置代理。windows需要设置相应的环境变量
1
2
go env -w GO111MODULE=on
go env -w GOPROXY=https://goproxy.io,direct

匿名函数

  • 普通函数变量
1
2
3
anon := func(a int,b int)int{
return a + b
}

anon是一个函数变量。

  • 函数返回函数
1
2
3
4
5
6
7
annof := func() func(int,int) int{
return func(a1 int, b1 int) int{
return a1 + b1
}
}
anon2 := annof()
}

anon2 也是一个匿名函数,该函数是返回一个函数。

  • 自启动。并且传参
1
2
3
4
5
6
anon3 := func(param string)func(int,int) int {
fmt.Println("param",param)
return func(a1 int,b1 int) int{
return a1 + b1
}
}("Hello World!")
  • 函数别名
1
2
3
4
5
6
type returnFunctionType func(int,int) int
anon4 := func() returnFunctionType {
return func(a1 int, b1 int) int{
return a1 + b1
}
}()
  • 调用函数
1
2
3
4
fmt.Println("anon func =",anon(1,2))
fmt.Println("anon func2 = ",anon2(1,2))
fmt.Println("anon func3 = ",anon3(1,2))
fmt.Println("anon func4 = ",anon4(1,2))
  • 调用结果
1
2
3
4
5
param Hello World!
anon func = 3
anon func2 = 3
anon func3 = 3
anon func4 = 3

闭包

  • 累加器
1
2
3
4
5
6
7
8
func addUper() func(int)int {
base := 10
return func(n1 int) int{
res := base + n1
base ++
return res
}
}

说明 改函数不依赖外部的数据实现累加。返回的func(int)int中含有一个base变量。该变量会自增。不会因为被调用而初始化。

  • 图片后缀
1
2
3
4
5
6
7
8
9
func suffixImage(s string) func(string)string {
return func(path string) string {
if strings.HasSuffix(path,s) {
return path
}else{
return path + s
}
}
}

说明 该函数返回一个闭包。能够识别是否拥有对应的后缀。没有就自己添加。

闭包总结

闭包等价于函数,但是该函数和普通的函数不一样的是,函数内部有一个不受外部影响而变化的变量。外部调用该函数时并不会重置该闭包内的数据。

接口和类型断言

1、接口

接口作为一种规范。接口是对继承的补充,并且通过接口可以实现上转型和下转型。golang的所有变量类型都是实现空接口,意味着可以将golang的各种类型上转成接口,然后再通过类型断言下转成具体类型。golang的空接口类似于java中的Object

1.1 接口的声明
1
2
3
4
type Usb interface {
Start()
Stop()
}

和java的接口一样,接口是作为一种规范,一个模板。没有具体的实现方式

1.2 接口的实现

和java不同的是,golang的接口实现不用显示的绑定,完全松耦合。只要一个类型或者变量实现了某个接口中定义的函数。即函数一样,就可以说该变量或者类型实现了该接口

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
type Phone struct{
name string
}
func (p Phone) Start() {
fmt.Println("手机开始工作。。。。")
}
func (p Phone) Stop() {
fmt.Println("手机停止工作....")
}
func (p Phone) Call() {
fmt.Println("手机打电话...")
}

type Camera struct{
name string
}
func (c Camera) Start() {
fmt.Println("相机开始工作。。。。")
}
func (c Camera) Stop() {
fmt.Println("相机停止工作")
}
func (c Camera) Photography(){
fmt.Println("拍照....")
}

类型Phone和Camera实现了Usb接口。但是看起来这两个类型没有和Usb这个接口联系起来。根本没有任何的绑定,java至少有implement来说明绑定的接口。唯一能和接口联系上的就是这两个类型都有Start()和Stop()函数。通过函数一样来绑定接口。

1.3 接口的使用

接口可以赋值,用具体实现类来赋值。这个和java的接口一致。可以使用接口类型来承接具体的类型

1
2
3
4
var usb Usb = Phone{name: "apple"}
fmt.Println(usb)
usb = Camera{name: "尼康"}
fmt.Println(usb)

usb的接口变量可以接收具体的实现类,接口会隐藏掉具体实现类中其它的特征,Phone中的Call()函数被隐藏了。

2、类型断言

类型断言类似于下转型,通过类型断言可以将接口下转成具体的实现类。实现接口的类型和断言的类型一致才会转换成功。
value,ok := i.(Phone)转换失败由第二个参数接收,转换成功由第一个参数接收转换后的具体实现类。

2.1 类型断言的使用(一)
1
2
3
4
5
6
7
8
9
10
11
12
13
type Computer struct{
}
func (c Computer) Working(usb Usb) {
usb.Start()
// 使用类型断言
if v,flag := usb.(Phone);flag{
v.Call()
}
if v, flag := usb.(Camera); flag {
v.Photography()
}
usb.Stop()
}

computer的Working(usb Usb)函数使用了,usb接口类型,如果传进来的实现类是Phone就调用Call()方法。如果是Camera就调用Photography()

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
var usbArr [3]Usb = [3]Usb{
0:Phone{
name: "vivo",
},
1:Camera{
name: "尼康",
},
2:Phone{
name: "meizu",
},
}
var computer Computer
for _,v := range usbArr{
computer.Working(v)
fmt.Println()
}

输出

1
2
3
4
5
6
7
8
9
10
11
手机开始工作。。。。
手机打电话...
手机停止工作....

相机开始工作。。。。
拍照....
相机停止工作

手机开始工作。。。。
手机打电话...
手机停止工作....
2.2 类型断言的使用(二)

使用一个类型判断函数

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
func TypeJudge(item... interface{}){
for index,v := range item{
switch v.(type) {
case bool:
fmt.Printf("第%v参数 bool类型,值为:%v\n",index,v)
case float32:
fmt.Printf("第%v参数 float32类型,值为:%v\n",index,v)
case float64:
fmt.Printf("第%v参数 float64类型,值为:%v\n",index,v)
case int, int32, int64:
fmt.Printf("第%v参数 int 类型,值为:%v\n",index,v)
case string:
fmt.Printf("第%v参数 string类型,值为:%v\n",index,v)
case Phone:
fmt.Printf("第%v参数 Phone类型,值为:%v\n",index,v)
case Camera:
fmt.Printf("第%v参数 Camera类型,值为:%v\n",index,v)
default:
fmt.Printf("第%v参数 未知类型,值为:%v\n",index,v)
}
}
}

调用函数

1
TypeJudge(1,"stringvalue",1.1,Phone{"phone"},Camera{"camera"},computer)

控制台输出

1
2
3
4
5
6
第0参数 int 类型,值为:1
第1参数 string类型,值为:stringvalue
第2参数 float64类型,值为:1.1
第3参数 Phone类型,值为:{phone}
第4参数 Camera类型,值为:{camera}
第5参数 未知类型,值为:{}

panic

捕获函数panic的defer必须在调用函数之前才能捕获。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
func TestPanic() {
//defer func() {
// if err := recover();err!= nil{
// fmt.Println("Function Catch Panic ",err)
// }
//}()
// 抛出panic
panic(errors.New("Test Panic"))
}
func main() {
// TestPanic() //无法捕获
// defer必须在TestPanic之前才能捕获
defer func() {
if err := recover();err!= nil{
fmt.Println("Main catch Panic ",err)
}
}()
TestPanic()
fmt.Println("over")
}

测试

当一个go文件以_test.go作为后缀的时候不会参与build.使用go test命令会执行里面的测试函数

  • 测试函数:以Test开始的函数,入参为(t *testing.T)
  • 基准测试:以Benchmark做前缀的函数,入参为(t *testing.B)
  • 示例函数:以Example做前缀的函数。入参为空。需要有注释//Output:作为输出结果。
例子
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
// 测试函数
func TestHelloWorld(t *testing.T) {
fmt.Println("Function Test Hello world")
}

func BenchmarkHello(t *testing.B) {
fmt.Println("Benchmark Test Hello")

}

func ExampleHello() {
//fmt.Println(false)
fmt.Println(true)
// Output:
// true
// false
}

命令行执行:go test就会执行测试函数。
添加-bench参数,启动bench测试。
go test -bench=.

Share 

 Previous post: go-mysql Next post: python aria2 rpc 

© 2025 long

Theme Typography by Makito

Proudly published with Hexo