常量、变量、函数、接口这些概念构成了一门程序设计语言的基础。go语言在传统的静态类型语言的基础上进行了部分改造,更符合实际工程应用需求。
常量的值在编译期就已经确定了,在整个程序运行过程中都不可以改变其值。 Go语言中的常量包括字面值常量、用户定义的常量和枚举。在go语言中没有枚举这种具体的类型,枚举的本质是一组常量。
字面值常量是在程序中硬编码的值,在go语言中字面值常量并没有具体的类型概念,字面值常量在可以赋值给任何类型值范围包含常量值的变量。
// 字面值常量赋值给整型变量
var intValue int = 100
fmt.Println("intValue:", intValue)
// 字面值常量赋值给浮点型变量
var floatValue float64 = 100
fmt.Println("floatValue:", floatValue)
go语言中的常量本质上是给字面值常量赋予一个用户友好的名称,通过关键字const定义一个常量。定义常量表达式的右值可以是任何在编译期可以确定值的表达式,如果右值是无法在编译期确定其值,编译器在编译程序时会发出错误提示。在使用const关键值定义常量时,可以显式指定常量的类型,如果没有显式指定常量的类型,那么该常量和字面值常量一样没有具体的数据类型。
// 定义常量时显式指定类型
const intConstValue int = 100
fmt.Println("intConstValue:", intConstValue)
// 定义常量时不显式指定类型
const constValue2 = 100
fmt.Println("constValue2:", constValue2)
// 同时定义多个不同类型的常量
const intConst1, floatConst = 100, 200.0
fmt.Println("intConst1:", intConst1)
fmt.Println("floatConst", floatConst)
go语言内置了true、false和iota三个常量。其中iota比较特殊,每次使用iota时值加一、在遇到下一个const关键字时重新变成零。如果连续定义多个常量都使用到了iota,那么在第一个常量的定义使用iota,余下的几个可以省略iota的使用。
// x1 == 0
const x1 = iota
fmt.Println("x1:", x1)
// x2 == 0
const x2 = iota
fmt.Println("x2:", x2)
const (
// x3 == 0
x3 = iota
// x4 == 1
x4 = iota
// x5 == 2
x5
)
fmt.Println("x3:", x3)
fmt.Println("x4:", x4)
fmt.Println("x5:", x5)
go语言并不像其他语言支持enum关键字,在go语言中枚举就是同时定义的一组常量。在定义的常量时候,常量名以大写字母开头表示该常量在其他package内也是可见的,如果常量名以小写字母开头表示该常量只在该package内可见。
// 定义星期枚举
const ( Sunday = iota
Monday
Tuesday
)
go语言通过引入关键字var声明一个变量。与其他静态类型语言声明变量不同,go语言在声明变量时变量名在前,变量类型在后。
// 声明一个变量
var hello int
// 给变量赋值
hello = 100
fmt.Println("hello:", hello)
// 同时声明两个变量
var(
v1 int
v2 string
)
v1 = 100
v2 = "Hello Go!"
fmt.Println("var1:", v1, "v2:", v2)
go语言的变量初始化和其他程序设计语言的变量初始化类似,但是go语言引入了:=符号,可以同时声明变量和初始化,不过:=符号左值必须是一个未声明过的变量。
// 声明一个变量
var hello int
// 给变量赋值
hello = 100
fmt.Println("hello:", hello)
test := "同时声明变量和初始化"
fmt.Println("test:", test)
go语言的变量赋值跟其他程序设计语言类似,不过go语言支持多变量同时赋值,该特性大大方便多个变量同时赋值。
var i = 100
var j = 200
fmt.Println("i:", i, "j:", j)
i, j = j, i
fmt.Println("i:", i, "j:", j)
go语言支持的基本数据类型包括:整型、布尔型、浮点型、复数类型、字符串和字符类型。支持的复合数据类型包括:指针、数组、切片、字典、通道、结构体和接口。
go语言中布尔类型使用关键字bool来标识,系统内置了两个布尔类型常量true和false。但是布尔类型变量不接受任何其他类型变量(常量)赋值,即使是强制类型转换,编译器也会报出类型错误。
var result bool = true
fmt.Println("result:", result)
// 右值可以是常量表达式(布尔值),但是不允许其他类型强制转换过来
var success bool = (1 > 0)
fmt.Println("success:", success)
go语言支持的整型类型比C++/Java要多,包括int8、 uint8、int16、int32、int64和int。其中int8占用8位,其他类型以此类推,但是int类型占用的字节数是随系统不同而不同,所以int32和int不是同一数据类型。
不同类型的整型数据之间是不能互相赋值的,如果有需求一定要赋值那么必须进行强制类型转换。
var v1 int16 = 32
var v2 int32 = 100
v2 = (int16) v1 //必须进行强制类型转换
go语言的整型数据支持+、-、*、/、%算术运算,支持>、>=、==、!=、<=、<这些判等运算符,同时支持位运算符<<、>>、&、|、^(取反)。
go语言浮点类型只有两种float32和float64,其中float32类似于C++/Java中的单精度浮点型、float64类似于C++/Java中双精度浮点型。
var floatValue1 float32
floatValue1 = 32.0
fmt.Println("floatValue1:", floatValue1)
// floatValue2 被自动推导为float64类型
floatValue2 := 32.0
fmt.Println("floatValue2:", floatValue2)
// floatValue1和floatValue2为不同类型
由于浮点型不是精确的数据值,所以比较两个浮点型数据时要比较两个值的差值是否落在业务接受的范围内。
go语言内置对复数类型的支持,复数由实部和虚部构成,可以通过real()和img()这两个函数获取复数类型的实部和虚部。
var complex1 complex64
complex1 = 1 + 100i
complex2 := 200 + 300i
fmt.Println("complex1:", complex1)
fmt.Println("complex2:", complex2)
fmt.Println("real:", real(complex1),"img:",imag(complex1))
go语言内置对字符串的支持,可以跟数组一样通过下标访问字符串的元素,go语言字符串元素在初始化后不允许进行修改。
import "fmt"
func main() {
var prefix string = "de-"
var content string = "registered"
result := prefix + content
fmt.Println("result:", result, "len:", len(content))
fmt.Printf("element 1 is: %c", result[1])
}
go字符串的遍历支持两种方式:通过类似字符串数组的方式进行遍历、通过range按unicode方式进行遍历
// 按字节数组方式访问,一个汉字对应多个字节
for i := 0; i < len(result); i++ {
fmt.Printf("index:%d, elem:%c!\n", i, result[i])
}
// 使用range,按unicode字符进行访问
for index, elem := range content {
fmt.Printf("index:%d, elem:%c.\n", index, elem)
}
go语言支持多维数组,数组的长度在定义的时候就固定下来。在定义数组的长度时可以使用编译期能确定下来的常量或则常量表达式,如果使用了编译期无法确定的值那么编译器会报错。访问go语言数组的方式也有两种,通过下标遍历数组元素和通过关键字range访问数组。
var array1 [10]int = [10]int{1, 2, 3, 4, 5, 6, 7, 8, 9, 0}
// 通过数组下标访问数组元素
for index := 0; index < len(array1); index++ {
fmt.Printf("index:%d, array1[%d] = %d.\n", index, index, array1[index])
}
// 通过range关键字遍历整个数组
for index, elem := range array1 {
fmt.Printf("index:%d, array1[%d] = %d.\n", index, index, elem)
}
go语言数组长度是内置的属性,可以通过len()直接获取数组的长度。在go语言中数组是值类型传递的,所以以数组作为函数实参传递的时候会发生值拷贝现象。
package main
import "fmt"
func main() {
var array1 [10]int = [10]int{1, 2, 3, 4, 5, 6, 7, 8, 9, 0}
changeElem(array1)
fmt.Println("The actual parameter is :")
// 数组为[1, 2, 3, 4, 5, 6, 7, 8, 9, 0]
for index, elem := range array1 {
fmt.Printf("index:%d, array1[%d] = %d.\n", index, index, elem)
}
}
func changeElem(array1 [10]int) {
// 数组为[1, 2, 3, 4, 5, 6, 7, 8, 9, 0]
fmt.Println("The parameter before modify is :")
for index, elem := range array1 {
fmt.Printf("index:%d, array1[%d] = %d.\n", index, index, elem)
}
// 数组变成[100, 2, 3, 4, 5, 6, 7, 8, 9, 0]
fmt.Println("The parameter after modify is :")
array1[0] = 100
for index, elem := range array1 {
fmt.Printf("index:%d, array1[%d] = %d.\n", index, index, elem)
}
}
数组在初始化以后就不能改变其长度,而且在作为实参传递的时候会发生值拷贝现象。数组切片是基于数组并且可以动态改变其长度,将数组切片作为函数的实参传递的时候是引用拷贝而不是值拷贝。
数组切片可以抽象出三个变量:
数组切片可以基于数组、数组切片创建,也可以通过使用make()函数创建。在使用make()函数创建数组切片的时候可以指定数组切片元素个数和数组切片的大小。
package main
import "fmt"
func main() {
var source [5]int = [5]int{0, 1, 2, 3, 4}
// 基于数组全部元素创建数组切片
var slice1 []int = source[:]
fmt.Println("slice1:", slice1)
// 基于数组前三个元素创建数组切片
var slice2 []int = source[:3]
fmt.Println("slice2:", slice2)
// 基于数组后四个元素创建数组切片
var slice3 []int = source[1:]
fmt.Println("slice3:", slice3)
// 创建五个元素的数组切片
slice4 := make([]int, 5)
fmt.Println("slice4:", slice4)
// 创建三个元素、六个元素空间的数组切片
slice5 := make([]int, 3, 6)
fmt.Println("slice5:", slice5)
// 直接创建数组切片
slice6 := []int{1, 2, 3, 4}
fmt.Println("slice6:", slice6)
}
数组切片元素的访问类似数组元素的访问,可以通过下标和range()关键字进行访问。
func main() {
var source [5]int = [5]int{0, 1, 2, 3, 4}
// 基于数组全部元素创建数组切片
var slice1 []int = source[:]
fmt.Println("slice1:", slice1)
// 基于数组切片下标访问
for index := 0; index < len(slice1); index++ {
fmt.Printf("%d ", slice1[index])
}
fmt.Println("")
// 基于range关键字访问
for _, elem := range slice1 {
fmt.Printf("%d ", elem)
}
}
数组切片常用的函数:
func main() {
var source [5]int = [5]int{0, 1, 2, 3, 4}
// 基于数组全部元素创建数组切片, len()函数获取数组切片元素个数、cap()函数获取数组切片大小
var slice1 []int = source[:]
fmt.Println("len:", len(slice1), "capacity:", cap(slice1), "slice1:", slice1)
// 给数组切片添加元素
slice1 = append(slice1, 100, 200, 300)
fmt.Println("len:", len(slice1), "capacity:", cap(slice1), "slice1:", slice1)
slice2 := []int{5, 6, 7, 8}
fmt.Println("len:", len(slice2), "capacity:", cap(slice2), "slice1:", slice2)
// 将slice1的前四个元素拷贝到slice2,copy()函数按slice1和slice2最小元素个数进行拷贝
copy(slice2, slice1)
fmt.Println("len:", len(slice2), "capacity:", cap(slice2), "slice1:", slice2)
}
go语言内置了字典数据类型,字典类型变量创建和获取都十分简洁、方便。
func main() {
var map1 map[int] string
map1 = make(map[int]string, 10)
map1[0] = "Hello"
map1[1] = "World"
map1[2] = "!"
fmt.Println("map1:", map1)
// 根据OK值判断是否取到值
value, ok := map1[0]
if ok == true {
fmt.Println("value:", value)
} else {
fmt.Println("Can not find any value!")
}
// 删除字典的一个元素,如果key指定的元素不存在,不会出现错误或则异常
delete(map1, 0)
elem, result := map1[0]
if result == true {
fmt.Println("elem:", elem)
} else {
fmt.Println("Can not find any elem!")
}
}