一直从事Java相关的工作,最近学习了go语言,作为没有接触过C的菜鸟刚开始撸go的时候还是有点不适应,废话不多说直接进入主题。
一、go简介
go是Google开发的一种编译型静态语言,语法简单,支持并发,相对于其他语言go的优点:
1)运行速度:可直接编译成机器代码直接执行,而java代码需要JVM加载字节码解释成机器码;
2)占用内存:go语言占用内存很小,节省了很大的内存空间,更轻量;
3)为并发而生:并发过程中,不同于java中的线程,go通过协程goroutine来实现并发,goroutine非常轻量;
在学习过程中,感觉go不太友好的地方(因为刚接触没多久,可能存在误解):
1)异常处理:go中所有的错误信息都是通过函数返回的error是否为nil,如果为nil说明发送异常然后进行相关操作,不同于java中可以捕获,还可以抛不同类型的异常,感觉没有java中的灵活;
2)对于每个包中只能有一个main方法,这很坑,在前期学习go的时候,感觉创建了N个包;
3)如果想添加第三方依赖虽然有go mod,但是感觉没有java中类似maven、gradle方便
二、go的基本语法
先看个hello world感受一下go世界
package main
import "fmt"
func main() {
fmt.Println("hello world")
}
package跟java一样有包的概念,不同的是java中的包名是包具体路径的名字,go中默认为main,表示当前是一个执行程序,可手动修改,如果修改后执行会报错。
package command-line-arguments is not a main package
import引入依赖库,其中fmt为包名,不能直接引入具体的文件,main()为主函数,程序的入口跟java一样,fmt.Println()打印hello world。
1、go中常用基本类型
布尔类型:bool
整型:int、int8、int16、int32、int64、uint、uint8、uint16、uint32、uint64
浮点:float32、float64
字符:char
字符串:string
复数:complex64、complex128
int类型在32位系统上是int32,表示有符号32位整型即4字节,和java中的int一样,在64位是int64与java中long一样,go还提供了无符号uint类型
其他类型:
指针类型
数组类型
切片类型
结构体类型
channel类型
map类型
接口类型
2、go变量
go中四种变量声明方式
// 1、声明变量默认值为0
var a int
// 2
var b int = 100
// 3
var c = 100
// 4、该方式只能用于局部变量,其他三种可以设置全局变量
d := 100
// 同时给多个变量赋值
var aa, bb int = 100, 200
var cc, dd = 100, "dd"
var (
ee int = 100
dd bool = true
)
go中常量使用const关键字,可通过iota自增
const length int = 100
const (
SUNDAY = iota // iota默认为0,每行自增1
MONDAY
TUESDAY
WEDNESDAY
...
)
3、go数组
// 固定数组
var myArray [4]int
for i := 0; i < len(myArray); i++ {
fmt.Println(i, ": ", myArray[i])
}
输出结果:
0 : 0
1 : 0
2 : 0
3 : 0
myArray1 := [4]int{}
for index, value := range myArray1 {
fmt.Println("index: ", index, "; value: ", value)
}
输出结果:
index: 0 ; value: 0
index: 1 ; value: 0
index: 2 ; value: 0
index: 3 ; value: 0
数组切片slice(无须设置数组长度)
slice1 := []int {1,2,3}
// 通过make关键字创建并且初始化数组
slice2 := make([]int, 3)
var numbers = make([]int, 3, 5) // 长度为3,容量为5,如果容量不够,会继续开辟5个空间
4、map
// map声明 1
var myMap1 map[string]string
//使用之前必须分配数据空间
myMap1 = make(map[string]string, 5)
// 2
myMap2 := map[string]string{
"one": "java",
}
// 3
myMap3 := make(map[string]string, 5)
//赋值、更新
myMap1["one"] = "golang"
//删除
delete(myMap1,"one")
//遍历
for key, value := range myMap1 {
fmt.Println("key: ", key, ", value: ", value)
}
5、函数、结构体
go中函数创建使用关键字func,defer在方法执行完成后执行,和java中的finally相似,可以同时写多个(存在多个defer时按照先写后执行的操作)。最后是先输出2222,在输出1111
func methodName(name string, age int) int {
fmt.Printf("name: %s, name: %d", name, age)
defer println("1111")
defer println("2222")
return age
}
go中使用struct关键字代替java中的类,go中没有private、protected、public等修饰词,通过变量名首字母来控制访问权限,如果是小写只能当前文件使用,如果是大写可以在同包不同的文件中使用
type Book struct {
Title string
auth string
}
// 声明对象
book := Book{Title: "golang", auth: "go"}
go中只需要在结构体中声明对象即可实现继承
type Animal struct {
name string
age int
}
type Bird struct {
Animal
fly string
}
func (bird *Bird) eat() {
fmt.Println(bird.Name, "eat bug")
}
//声明
bird := Bird{Animal{
Name: "xique",
Age: 1,
}, "flying"}
bird.eat();
除了继承,go也支持接口,不同于java,go无须强制实现,定义的结构体只需要全部实现所有接口中的方法即实现了该接口
type Animal interface {
eat()
sleep()
}
type Dog struct {
name string
color string
}
func (dog *Dog) sleep() {
fmt.Println("sleep...")
}
func (dog *Dog) eat() {
fmt.Println("eat...")
}
//声明
var animal Animal
animal = &Dog{}
animal.eat()
5、goroutine
go天生支持并发,goruntine也称为go协程
go func() {
fmt.Println("start execute goroutine...")
}()
协程之间可通过channel进行通信,channel包括无缓冲和有缓冲两种方式
myChan <-:向管道中填充数据 <-myChan:从管道中取数据
func main() {
myChan := make(chan string)
go func() {
fmt.Println("start execute goroutine...")
myChan <- "end" //(1)
}()
result := <- myChan //{2}
fmt.Println(result)
}
无缓冲区和有缓冲区的区别:
1)无缓冲区如果没有数据读操作会发送阻塞,比如上面的例子(2)会一直阻塞,直到(1)写操作完成后,才会执行,同样如果里面有数据了写操作也会阻塞,直到为空才会执行。
2)有缓冲如果没有数据读也会阻塞,但是如果里面有数据写不会阻塞直到写满后才会阻塞写操作;
//定义有缓冲区的chan
myChan := make(chan string, 3)
go中所有的错误处理都是通过函数返回来进行判断,如果返回的err!=nil说明发送错误,然后进行处理。
// 建立socket连接
conn, err := net.Dial("tcp", fmt.Sprintf("%s:%d", ip, port))
if err != nil {
fmt.Println("client dial error: ", err)
}
make与new的区别:
make只能创建slice切片、map、chan的初始化,make返回的是Type数据类型,new返回的是*Type指针类型,需要手动进行初始化。
// 使用new创建的map在使用之前必须要进行初始化
myMap := new(map[string]string)
*myMap = map[string]string{}
(*myMap)["a"] = "a"
// make创建的map已经完成初始化,可以直接使用
myMap2 := make(map[string]string)
myMap2["one"] = "golang"