1 基础数据类型

1.1 分类

""

int和uint(有符号整数 / 无符号整数):根据底层平台,表示32位或者65位整数。除非使用非常大的整数,否则通常使用int来表示整数。

1.1.1 类型应用

// 布尔类型
var b bool = false

// 整型
var i int = 10

// 浮点型
var f float = 3.14
f2 := 12.0

1.1.2 字符串型

""
//1. 定义字符串
var s1 string
s1 = "张三"
fmt.Printf("%T,%s\n", s1, s1)

s2 := `hello world`
fmt.Printf("%T,%s\n", s2, s2)
区别
package main
import "fmt"

func main(){
	//2. 区别'A', "A"
	v1 := 'A'
	v2 := "A"

	fmt.Printf("%T, %d\n", v1, v1)
	fmt.Printf("%T, %s\n", v2, v2)
	
	v3 := '中'
	fmt.Printf("%T, %d, %c, %q\n", v3, v3, v3, v3)
}

控制台输出:

$ go run xxx.go
int32, 65
string, A
int32, 20013, 中, '中'

1.1.3 数据类型转换

Type(Value)T(V)

注意点:兼容类型可以互相转换

package main
import "fmt"

func main(){
	var a int8
	a = 10

	var b int16
	b = int16(a)
	fmt.Println("a = ", a)
	fmt.Println("b = ", b)

	f1 := 4.83
	var c int
	c = int(f1)
	fmt.Println("c = ", c)
}

控制台输出:

$ go run xxx.go
a =  10
b =  10
c =  4
2 复合数据类型

包括:

  • 指针类型(Pointer)
  • 数组类型
  • 结构化类型(struct)
  • Channel 类型
  • 函数类型
  • 切片类型
  • 接口类型(interface)
  • Map 类型

2.1 数组(Array)

Go语言提供了数组类型的数据结构。

数组是具有相同唯一类型的一组已编号且长度固定的数据项序列,这种类型可以是任意的原始类型例如整型、字符串或者自定义类型。

数组元素可以通过索引(位置)来读取(或者修改),索引从0开始,第一个元素索引为0。

数组一旦定义后,大小不能更改。

2.1.1 数组的语法

声明和初始化数组

需要知名数组的大小和存储的数据类型。

 variable_name [SIZE] variable_type

示例代码:

package main
import "fmt"

func main() {
	//1. 创建数组
    var arr1 [5]int
    arr1[0] = 1
    arr1[1] = 2
    arr1[2] = 3
    arr1[3] = 4
    arr1[4] = 5

    fmt.Println("arr1的长度是:", len(arr1))
    fmt.Println("arr1的容量是:", cap(arr1))
}

结果输出:

$ go run xxx.go
arr1的长度是: 5
arr1的容量是: 5

数组其他创建方式:

var a [10]float32
fmt.Println(a)

var b = [5]float32{1000.0, 2.0, 3.4, 7.0, 50.0}
fmt.Println(b)

var c = [5]int{1, 2, 4}
fmt.Println(c)

var d = [5]int{1:1, 3:2}
fmt.Println(d)

var e = []int{6, 7, 8, 9, 10}
fmt.Println(e)

结果输出:

$ go run xxx.go

[0 0 0 0 0]
[1000 2 3.4 7 50]
[1 2 4 0 0]
[0 1 0 2 0]
[6 7 8 9 10]

2.1.2 数组拷贝是值传递,深拷贝

	var e = [5]int{6, 7, 8, 9, 10}
	fmt.Println("e = ", e)

	var f [5]int
	f = e  // 值传递	
	f[1] = 1
	
	fmt.Println("e = ", e)
	fmt.Println("f = ", f)
	fmt.Println("f == e ? ", e == f)

	var d = [5]int{1:1, 3:2}
	fmt.Println("d = ", d)

	g := d // 值传递
	g[1] = 2
	fmt.Println("d = ", d)
	fmt.Println("g = ", g)
	fmt.Println("g == d ? ", d == g)

结果输出:

e =  [6 7 8 9 10]
e =  [6 7 8 9 10]
f =  [6 1 8 9 10]
f == e ?  false

d =  [0 1 0 2 0]
d =  [0 1 0 2 0]
g =  [0 2 0 2 0]
g == d ?  false

2.1.3 多维数组

2.2 切片(slice)

2.2.1 什么是切片

Go语言切片是对数组的抽象。

"动态数组"
[]
三个元素
  • 指针,指向数组中slice指定的开始位置
  • 长度,即slice的长度
  • 最大长度,也就是slice开始位置到数组最后位置的长度
package main
import "fmt"

func main() {

	/*
	数组array:
	存储一组相同数据类型的数据结构
		特点:定长

	切片slice:
		同数组类似,也叫做变长数组或者动态数组
			特点:变长
		是一个引用类型的容器,指向了一个底层数组
	
	makde()
		func make(t Type,size ... IntegerType) Type
		第一个参数:类型
			slice,map,chan
		第二个参数:长度len
			实际存储元素的数量
		第三个参数:容量cap
			最多能够存储的元素的数量
	*/
	
	//1. 数组
	arr := [4]int{1,2,3,4}
	fmt.Println(arr)

	//2. 切片
	var s1 []int
	fmt.Println(s1)

	s2 := []int{1,2,3,4}
	fmt.Println(s2)
	fmt.Printf("arr type is %T,s2 type is %T\n", arr, s2)

	s3 := make([]int, 3, 8)
	fmt.Println(s3)
	fmt.Printf("s3 容量:%d, 长度: %d\n", cap(s3), len(s3))
}

结果输出:

[1 2 3 4]
[]
[1 2 3 4]
arr type is [4]int,s2 type is []int
[0 0 0]
s3 容量:8, 长度: 3

2.2.2 append

两种方法:

slice = append(slice, elem1, elem2)
slice = append(slice, anotherslice...)

实例:

package main
import "fmt"

func main() {
	s3 := make([]int, 3, 8)
	fmt.Println(s3)
	fmt.Printf("s3 容量:%d, 长度: %d\n", cap(s3), len(s3))
	s3[0] = 1
	s3[1] = 2
	s3[2] = 3
	fmt.Println(s3)
	//fmt.Println(s3[3]) runtime error: index out of range [3] with length 3

	//append elem
	s4 := make([]int, 0, 5)
	fmt.Println(s4)
	s4 = append(s4, 1, 2)
	fmt.Println(s4)
	s4 = append(s4, 3, 4, 5, 6) // 添加超过最大cap的数量
	fmt.Println(s4)
	
	//append anotherslice
	s4 = append(s4, s3...)
	fmt.Println(s4)
}

结果输出:

[0 0 0]
s3 容量:8, 长度: 3
[1 2 3]
[]
[1 2]
[1 2 3 4 5 6]
[1 2 3 4 5 6 1 2 3]

2.2.3 slice自动扩容

/*
切片slice:
	1. 每一个切片引用了一个底层数组
	2. 切片本身不存在任何数据,都是这个底层数组存储,所以修改切片也就是修改这个数组中的数据
	3. 当向切片中添加数据时,如果没有超过容量,直接添加,如果超过容量,自动扩容(原容量 × 2)
	4. 切片一旦扩容,就是重新指向了一个新的底层数组
*/
s1 := []int{1, 2, 3}
fmt.Println(s1)
fmt.Printf("len:%d,cap:%d\n", len(s1), cap(s1))	//len:3,cap:3
fmt.Printf("%p\n", s1)

s1 = append(s1, 4, 5)
fmt.Println(s1)
fmt.Printf("len:%d,cap:%d\n", len(s1), cap(s1)) //len:5,cap:6
fmt.Printf("%p\n", s1)

s1 = append(s1, 6, 7, 8)
fmt.Println(s1)
fmt.Printf("len:%d,cap:%d\n", len(s1), cap(s1)) //len:8,cap:12
fmt.Printf("%p\n", s1)

结果输出:

[1 2 3]
len:3,cap:3
0xc0000b6000
[1 2 3 4 5]
len:5,cap:6
0xc0000aa030
[1 2 3 4 5 6 7 8]
len:8,cap:12
0xc00008c060

2.2.4 数组切片初始化

s :=[] int {1,2,3 } 
[]cap=len=3
s := arr[:] 

初始化切片 s,是数组 arr 的引用。

s := arr[startIndex:endIndex] 
startIndexendIndex-1
s := arr[startIndex:] 

默认 endIndex 时将表示一直到arr的最后一个元素。

s := arr[:endIndex] 

默认 startIndex 时将表示从 arr 的第一个元素开始。

s1 := s[startIndex:endIndex] 
切片 s
s :=make([]int,len,cap) 
make()[]int

2.3 Map

Map 是一种无序的键值对的集合。Map 最重要的一点是通过 key 来快速检索数据,key 类似于索引,指向数据的值。

Map 是一种集合,所以我们可以像迭代数组和切片那样迭代它。不过,Map 是无序的,我们无法决定它的返回顺序,这是因为 Map 是使用 hash 表来实现的。

2.3.1 定义 Map

可以使用内建函数 make 也可以使用 map 关键字来定义 Map:

/* 声明变量,默认 map 是 nil */
var map_variable map[key_data_type]value_data_type

/* 使用 make 函数 */
map_variable := make(map[key_data_type]value_data_type)

示例:

package main
import "fmt"

func main() {
	var map1 map[string]int  //没有初始化
	var map2 = make(map[string]int) //创建
	map2["xiaoming"] = 1
	
	var map3 = map[string]int{"Go":98, "Python":87, "Java":79, "Html":93}


	fmt.Println(map1)
	fmt.Println(map2)
	fmt.Println(map3)

	fmt.Println(map1 == nil)
	fmt.Println(map2 == nil)
	fmt.Println(map3 == nil)

	if map1 == nil {
		map1 = make(map[string]int)
		fmt.Println(map1)
	}
}

输出:

map[]
map[xiaoming:1]
map[Go:98 Html:93 Java:79 Python:87]
true
false
false
map[]

2.3.2 Map的使用

package main
import "fmt"

func main() {
	//创建
	var map1 = make(map[string]int) 

	//修改数据
	map1["xiaoming"] = 18
	map1["xiaohong"] = 17
	map1["xiaolan"] = 16

	fmt.Println(map1)

	//删除数据delete
	delete(map1,"xiaoming")
	fmt.Println(map1)

	//长度
	fmt.Println(len(map1))
}

结果输出:

map[xiaohong:17 xiaolan:16 xiaoming:18]
map[xiaohong:17 xiaolan:16]
2

2.3.3 Map的遍历

	var map1 map[string]int /*创建集合 */
    map1 = make(map[string]int)

    /* map插入key - value对,各个国家对应的首都 */
    map1 [ "France" ] = 1
    map1 [ "Italy" ] = 2
    map1 [ "Japan" ] = 3
    map1 [ "India " ] = 4

    /*使用键输出地图值 */
    for k, v := range map1 {
        fmt.Println(k, "---->", v)
    }

	for k := range map1 {
		fmt.Println(k, "---->", map1[k])
	}

结果输出:

France ----> 1
Italy ----> 2
Japan ----> 3
India  ----> 4

India  ----> 4
France ----> 1
Italy ----> 2
Japan ----> 3

2.3.4 判断key是否存在

判断American是否存在

package main
import "fmt"

func main() {
	var map1 map[string]int /*创建集合 */
    map1 = make(map[string]int)

    /* map插入key - value对,各个国家对应的首都 */
    map1 [ "France" ] = 1
    map1 [ "Italy" ] = 2
    map1 [ "Japan" ] = 3
    map1 [ "India " ] = 4

	/*查看元素在集合中是否存在 */
    capital, ok := map1 [ "American" ] /*如果确定是真实的,则存在,否则不存在 */
    /*fmt.Println(capital) */
    /*fmt.Println(ok) */
    if (ok) {
        fmt.Println("American :", capital)
    } else {
        fmt.Println("American 不存在")
    }
}

结果输出:

American 不存在

2.3.5 map结合slice使用

用例:将map中的信息统一打印

package main
import "fmt"

func main() {
	//第一个人
	map1 := make(map[string]string)
	map1["name"] = "王二狗"
	map1["age"] = "30"
	map1["sex"] = "男性"
	map1["address"] = "北京市XX路XX号"

	//第二个人
	map2 := make(map[string]string)
	map2["name"] = "李小花"
	map2["age"] = "20"
	map2["sex"] = "女性"
	map2["address"] = "上海市XX路XX号"

	//第三个人
	map3 := map[string]string{"name":"ruby","age":"30","sex":"女性","address":"杭州市"}

	//将map存到slice中
	s1 := make([]map[string]string, 0, 3)
	s1 = append(s1, map1)
	s1 = append(s1, map2)
	s1 = append(s1, map3)

	//便利切片
	for i, val := range s1 {
		//val: map1, map2, map3
		fmt.Printf("第%d个人的信息是:\n", i)
		fmt.Printf("\t姓名:%s\n", val["name"])
		fmt.Printf("\t年龄:%s\n", val["age"])
		fmt.Printf("\t性别:%s\n", val["sex"])
		fmt.Printf("\t地址:%s\n", val["address"])
	}
}

结果输出:

第0个人的信息是:
	姓名:王二狗
	年龄:30
	性别:男性
	地址:北京市XX路XX号
第1个人的信息是:
	姓名:李小花
	年龄:20
	性别:女性
	地址:上海市XX路XX号
第2个人的信息是:
	姓名:ruby
	年龄:30
	性别:女性
	地址:杭州市