变量
变量声明
var v1 int
var v2 string
var v3 [10]int // 数组
var v4 []int // 数组切片
var v5 struct {
f int
}
var v6 *int // 指针
var v7 map[string]int // map, key为string类型, value为int类型
var v8 func(a int) int
在go语言中,并不需分号作为结束符,并且在go语言中,引入了var关键字,类型名称放在变量名称之后
为了避免大量的重复var。还可以写成下面的方式声明变量,
var (
v1 int
v2 string
)
变量初始化
var v1 int = 10 // 正确的使用方式1
var v2 = 10 // 正确的使用方式2,编译器可以自动推导出v2的类型
v3 := 10 // 正确的使用方式3,编译器可以自动推导出v3的类型
上面三种方式都是go语言声明变量的正确方式,可以看见,第三种方式大大减少了字符量,其中:=
表示的是同时进行声明和初始化工作
。需要注意的是,:=
左边的的变量不能是已经被声明过的,如下:
var i int
i := 2
这样会编译错误
变量赋值
var v10 int
v10 = 123
需要注意的是:在go语言中,变量声明和变量赋值是两个不同的概念,同时在go语言中,可以实现多重赋值功能,比如下面交换变量i和变量j的语句:
i, j = j, i
和其他编程语言相比,真是太好用了,
匿名变量
//假 设 GetName() 函 数 的 定 义 如 下 , 它 返 回 3 个 值 , 分 别 为firstName 、 lastName 和
nickName:
func GetName() (firstName, lastName, nickName string) {
return "May", "Chan", "Chibi Maruko"
}
如果想要只是获得nickName ,则只需要以下语句即可:
_, _, nickName := GetName()
go语言的这种写法,不会像其他语言那样,声明一大堆无用的变量
go语言的这种写法让代码十分德尔简洁,便于阅读,理解和维护。
常量
字面常量
字面常量通常是指程序中硬编码的常量
,在其他语言中,常量都有特定的类型,比如int、long、float等等。但是在go语言中,常量是没有类型的,只要这个常量在相应类型的值域范围内,就可以作为该类型的常量,比如上面的常量-12,它可以赋值给int、 uint、 int32、int64、 float32、 float64、 complex64、 complex128等类型的变量。
常量的定义
在g语言中通过const关键字来定义常量,如下:
const Pi float64 = 3.14159265358979323846
const zero = 0.0 // 无类型浮点常量
const (
size int64 = 1024
eof = -1 // 无类型整型常量
)
const u, v float32 = 0, 3 // u = 0.0, v = 3.0,常量的多重赋值
const a, b, c = 3, 4, "foo"
// a = 3, b = 4, c = "foo", 无类型整型和字符串常量
同时,在go语言中,也是可以定义类型的, 但是不是必须定义。
预定义常量
Go语言预定义了这些常量: true、 false和iota
iota
是什么:
iota是一个可被编译器修改的常量,在每一个const关键字出现时被重置为0,然后在下一个const出现之前,每出现一次iota,其所代表的数字会自动增1
const ( // iota被重设为0
c0 = iota // c0 == 0
c1 = iota // c1 == 1
c2 = iota // c2 == 2
)
const (
a = 1 << iota // a == 1 (iota在每个const开头被重设为0)
b = 1 << iota // b == 2
c = 1 << iota // c == 4
)
const (
u = iota * 42 // u == 0
v float64 = iota * 42 // v == 42.0
w = iota * 42 // w == 84
)
const x = iota // x == 0 (因为iota又被重设为0了)
const y = iota // y == 0 (同上)
如果两个const的赋值语句的表达式是一样的,那么可以省略后一个赋值表达式。
const ( // iota被重设为0
c0 = iota // c0 == 0
c1 // c1 == 1
c2 // c2 == 2
)
const (
a = 1 <<iota // a == 1 (iota在每个const开头被重设为0)
b // b == 2
c // c == 4
)
枚举
枚举指一系列相关的常量
在go语言中,并不存在其中语言中的枚举关键字enum
如下面是一个表示星期的枚举:
const (
Sunday = iota
Monday
Tuesday
Wednesday
Thursday
Friday
Saturday
numberOfDays // 这个常量没有导出
)
在这里需要注意的是:在go语言中,以大写字母开头的常量,在其他包中可见,以小写字母开头的常量,只能在本包中可见,在其他包中不可见。所以上面的numberOfDays
不能够被其他包导出。
类型
go语言中的类型有下面几种:
布尔类型: bool。
整型: int8、 byte、 int16、 int、 uint、 uintptr等。
浮点类型: float32、 float64。
复数类型: complex64、 complex128。
字符串: string。
字符类型: rune。
错误类型: error。
同时go语言也支持下面的几种复合类型:
指针(pointer)
数组(array)
切片(slice)
字典(map)
通道(chan)
结构体(struct)
接口(interface)
同时go语言也有封装int、 uint和uintptr等类型,在常规的开发中,用到int等类型即可。
布尔类型
var v1 bool
v1 = true
v2 := (1 == 2) // v2也会被推导为bool类型
在go语言中,和其他语言一样,布尔类型不能接受其他类型的赋值,不支持自动或强制的类型转换
整型
需要注意的是int和int32是不同的类型,两个不同类型的整型数不能直接比较
位运算
浮点型:
Go语言定义了两个类型float32和float64,其中float32等价于C语言的float类型,float64等价于C语言的double类型。
var fvalue1 float32
fvalue1 = 12
fvalue2 := 12.0 // 如果不加小数点, fvalue2会被推导为整型而不是浮点型
因为浮点数不是一种精确的表达方式,所以像整型那样直接用==来判断两个浮点数是否相等是不可行的,这可能会导致不稳定的结果
下面是一种替换方案;
import "math"
// p为用户自定义的比较精度,比如0.00001
func IsEqual(f1, f2, p float64) bool {
return math.Fdim(f1, f2) < p
}
复数类型:
var value1 complex64 // 由2个float32构成的复数类型
value1 = 3.2 + 12i
value2 := 3.2 + 12i // value2是complex128类型
value3 := complex(3.2, 12) // value3结果同 value2
在go语言中,如果复数表示为:z = complex(x, y),那么:real(z)获得实部x,imag(z)获得虚部y。
字符串
var str string // 声明一个字符串变量
str = "Hello world" // 字符串赋值
ch := str[0] // 取字符串的第一个字符
fmt.Printf("The length of \"%s\" is %d \n", str, len(str))
fmt.Printf("The first character of \"%s\" is %c.\n", str, ch)
打印的结果为:
go语言中字符串的操作
go语言中遍历字符串
str := "Hello,世界"
n := len(str)
for i := 0; i < n; i++ {
ch := str[i] // 依据下标取字符串中的字符,类型为byte
fmt.Println(i, ch)
}
打印结果:
字符类型:
go语言中的字符类型:一个是byte(实际上是uint8的别名),代表UTF-8字符串的单个字节的值;另一个是rune,代表单个Unicode字符。
数组:
[32]byte // 长度为32的数组,每个元素为一个字节
[2*N] struct { x, y int32 } // 复杂类型数组
[1000]*float64 // 指针数组
[3][5]int // 二维数组
[2][2][2]float64 // 等同于[2]([2]([2]float64))
go语言中国数组长度定义之后不可修改,使用arrLength := len(arr)
表示获取获得arr数组元素个数。
遍历数组的方法:
for i := 0; i < len(array); i++ {
fmt.Println("Element", i, "of array is", array[i])
}
在go语言中还有一个range关键字。用于便捷的遍历数组
for i, v := range array {
fmt.Println("Array element[", i, "]=", v)
}
在go语言中,数组是一个值类型:
数组切片
一个指向原生数组的指针;
数组切片中的元素个数;
数组切片已分配的存储空间。
数组切片弥补了数组中的不足。
数组切片添加了一系列管理功能,可以随时动态扩充存放空间,并且可以被随意传递而不会导致所管理的元素被重复复制。
// 先定义一个数组
var myArray [10]int = [10]int{1, 2, 3, 4, 5, 6, 7, 8, 9, 10}
// 基于数组创建一个数组切片
var mySlice []int = myArray[:5]
fmt.Println("Elements of myArray: ")
for _, v := range myArray {
fmt.Print(v, " ")
}
fmt.Println("\nElements of mySlice: ")
for _, v := range mySlice {
fmt.Print(v, " ")
}
fmt.Println()
map
map是一堆键值对的未排序集合
// PersonInfo是一个包含个人详细信息的类型
type PersonInfo struct {
ID string
Name string
Address string
}
func main() {
var personDB map[string]PersonInfo
personDB = make(map[string]PersonInfo)
// 往这个map里插入几条数据
personDB["12345"] = PersonInfo{"12345", "Tom", "Room 203,..."}
personDB["1"] = PersonInfo{"1", "Jack", "Room 101,..."}
// 从这个map查找键为"1234"的信息
person, ok := personDB["1234"]
// ok是一个返回的bool型,返回true表示找到了对应的数据
if ok {
fmt.Println("Found person", person.Name, "with ID 1234.")
} else {
fmt.Println("Did not find person with ID 1234.")
}
}
声明变量
var myMap map[string] PersonInfo
创建
可以使用Go语言内置的函数make()来创建一个新map
myMap = make(map[string] PersonInfo)
也可以选择是否在创建时指定该map的初始存储能力,下面的例子创建了一个初始存储能力为100的map:
myMap = make(map[string] PersonInfo, 100)
创建并初始化:
myMap = map[string] PersonInfo{
"1234": PersonInfo{"1", "Jack", "Room 101,..."},
}
赋值
myMap["1234"] = PersonInfo{"1", "Jack", "Room 101,..."}
删除
delete(myMap, "1234")
delete()是go语言中的一个内置函数,用于删除容器中的内容。
元素查找:
value, ok := myMap["1234"]
if ok { // 找到了
// 处理找到的value
}
判断是否成功找到特定的键,不需要检查取到的值是否为nil,只需查看第二个返回值ok。