golang中主要基础数据类型如下:
类型 | 描述 |
---|---|
uint8 | 无符号 1个字节8位整型 (0 到 255) |
uint16 | 无符号 2字节16位整型 (0 到 65535) |
uint32 | 无符号 4字节32位整型 (0 到 4294967295) |
uint64 | 无符号 8字节64位整型 (0 到 18446744073709551615) |
int8 | 有符号 1字节8位整型 (-128 到 127) |
int16 | 有符号 2字节16位整型 (-32768 到 32767) |
int32 | 有符号 4字节32位整型 (-2147483648 到 2147483647) |
int64 | 有符号 8字节64位整型 (-9223372036854775808 到 9223372036854775807) |
uint | 32位操作系统上就是uint32,64位操作系统上就是uint64 |
int | 32位操作系统上就是int32,64位操作系统上就是int64 |
float32 | 32 位浮点型 |
float64 | 64 位浮点型 |
complex64 | 32 位实数和虚数 |
complex128 | 64 位实数和虚数 |
uintptr | 无符号整型,用于存放一个指针 |
bool | 1字节8位,只允许 true和false不能转int,默认值为false |
string | 默认值为 “” |
变量定义
golang中可以通过如下几种方式对变量进行定义:
- var name type 方式,这种情况下,变量的值为其零值,比如:
var a int;
var b int = 3
如果指定了其初始值,那么不用指定类型,形如: var name = value 格式,如:
var a = 100
- name : = value 格式,
这种只能在函数内部用
,使用:=
,golang会自动推导其类型
a := 100
- 一次定义多个变量,按照从左到右的方式赋值:
var a, b, c int
var a, b, c int = 1,2,3
var a, b, c = 1,2,3
a,b,c := 1,2,3 // 必须在方法内部使用
- 使用var () 一次定义多个:
var (
a int
b string
c []float32
...
)
数组
golang中数组声明如下:
var name [size]type
如:
var arr [2]int
声明了一个长度为2类型为int的数组,数组中的每个元素初始值都为0
或者:
arr := [...]int{1,2,3,4}
brr := [3]int{1,2,3}
切片
golang中切片声明如下:
var name []type
如:
var sli []int
还可以通过如下方式:
var slicea []int = arr[0:1] // arr[:]复制所有
sliceb := make([]int,5,5)
指针
我们知道golang中很多函数都是基于值传递的,需要进行复制,如果对象比较大,那么比较耗时,这时候我们可以使用指针,指针对应的内存中存储的是实际变量的地址,这样当我们进行函数调用传递指针(也是值复制,但是这里复制的是一个指针),我们就不用复制整个数据类型,而只用复制指针即可,然后通过指针能够对原有对象进行访问。
一般指针生命如下:
var pName *type
指针类型与一般类型的最大区别就是增加了一个*
来表明这是一个指针类型。而指针类型进行初始化则需要配合取地址运算符&
:
var age int = 20;
var pAge *int =&age;
访问指针内容,也是使用*
:
var age int =20
var pAge *int = &age
*pAge = 30
fmt.Print(age)
通道
golang中通道主要是用来goroutine之间用进行通信的工具,通道一般可以声明如下:
var chanName chan type
比如:
var message chan int;
message = make(chan int)
通过到通过make进行初始化
向通道发送数据通过<-
进行发送:
var message chan int;
message = make(chan int)
message <- 20
接收通道数据同样使用操作符<-
data := <- message
如果我们想要忽略接收数据
,则可以如下操作:
<- message
data := <- message
执行时,如果没有数据,则会阻塞,完整写法如下:
data,ok := <- messag
ok为bool类型
,通过ok可以判断通道是否被关闭。
另外,如果没有接收到数据,则data默认为data类型的零值
如果需要循环接收数据,则可以通过for循环和for range进行循环接收数据:
// example 1
for {
data := <- message
if data == 0 {
break
}
fmt.Println("receive data from chan: ",data)
}
// example 2
for {
data,ok := <- message
if !ok {
fmt.Println("chan is closed")
break
}
fmt.Println("receive data from chan: ",data)
}
// example 3
for data := range message {
fmt.Println("receive data from chan: ",data)
}
这其中for range
方式能够自动判断通道是否关闭
需要注意的是通道默认是阻塞的,当数据发送到通道中通道发生阻塞知道其他goroutine从通道中读取数据。当从通道中读取数据时也会被阻塞知道其他goroutine将数据写入到该通道中,通过这种机制,通道能够帮助goroutine实现类似锁的机制
默认创建通道的方式是不带有缓冲区的,读写都是即时阻塞。我们可以创建带有缓冲区的通道,这样当缓冲区未满时,读写都是非阻塞的
,创建缓冲通道示例如下:
var message chan int;
message = make(chan int,10)
默认通道都是双向的,可读可写,我们也可以指定通道的方向也就是通道的读写性,一般这种特性主要是用于函数的参数,确保在函数内只能读取或者写入数据到通道中
。
//读通道
var readChan <- chan int
readChan = make(<- chan int)
//写通道
var writeChan chan <- int
writeChan = make(chan <- int)
我们需要注意的是,由于通道的阻塞特性,如果通道一直没有写入或者读取数据,会导致通道相关的goroutine陷入死锁,这个我们后面再单独讨论
结构体
golang中结构体定义如下:
type name struct {
filedName1 type
filedName2 type
....
}
可以通过如下方式进行初始化:
type Person struct{
Name string
Age int
}
var person Person;
person.Name = "leo"
person.Age = 31
或者:
var person = Person{Name:"leo",Age:31}
// 或者
person := Person{Name:"leo",Age:31}
或者使用new函数,但是返回的是一个指针
person := new(Person)
接口
golang中接口一般定义如下:
type interName interface{
Method1(arg1 type1,arg2 typ2)(type3,typ4)
Method2(arg1 type1,arg2 typ2)(type3,typ4)
}
可见性
在golang中,struct中成员、函数以及包的变量和函数如果首字母大写,则都是public,否则都是对外不可见的
值传递、指针传递
golang中默认都是值传递的,即拷贝传递,有一些值是指针,也是拷贝指针的值传递,只是通过指针可以修改原有数据