Go语言从入门到达人--复合数据类型

数组
数组是固定长度且拥有零个或者多个相同数据类型元素序列,由于数组固定长度,所以GO语言中很少用,基本都是使用slice长度可变长度和缩短

package main

import "fmt"

func main() {
	var a [3]int
	fmt.Println(a[0])
	fmt.Println(a[len(a) - 1])

	for i,v := range a{
		fmt.Printf("%d %d\n",i,v)
	}
	for _,v := range a{
		fmt.Println(v)
	}

}

输出结果

GOROOT=D:\Go #gosetup
GOPATH=D:\Go;D:\gin #gosetup
D:\Go\bin\go.exe build -o C:\Users\Administrator\AppData\Local\Temp\___1go_build_arrayList_go.exe D:/gin/arrayList.go #gosetup
C:\Users\Administrator\AppData\Local\Temp\___1go_build_arrayList_go.exe #gosetup
0
0
0 0
1 0
2 0
0
0
0

Process finished with exit code 0

package main

import "fmt"

func main() {

	var q [3]int = [3]int{1,2,3}
	var r [3]int = [3]int{1,2}
	fmt.Println(r[2],q[2])

}

输出 0 3
其实上面的例子很明白,定义了固定长度的数据,没有定义数值0补充
记住数组的长度也是数据类型的一部分,所以[3]int [4]int是两种不同的数据类型,数组长度必须是常量表达式

slice
slice表示一个拥有相同类型元素的可变长度的序列。slice通常写成[]T,其中元素类型都是T,可以说slice是底层的数组
slice[i:j]其实是,slice从i到j-1索引位置的所有元素,也是说含左不含右

package main

import "fmt"

func main() {
	months := []string{1:"January",2:"February",3:"March",4:"April",5:"May",6:"June",7:"July",8:"August",9:"September",10:"Ortobor",11:"November",12:"December"}
	Q2 := months[1:10]
	fmt.Println(Q2)

}

GOROOT=D:\Go #gosetup
GOPATH=D:\Go;D:\gin #gosetup
D:\Go\bin\go.exe build -o C:\Users\Administrator\AppData\Local\Temp\___2go_build_arrayList_go.exe D:/gin/arrayList.go #gosetup
C:\Users\Administrator\AppData\Local\Temp\___2go_build_arrayList_go.exe #gosetup
[January February March April May June July August September]

Process finished with exit code 0

查找月份相同的元素

package main

import "fmt"

func main() {
	months := []string{1:"January",2:"February",3:"March",4:"April",5:"May",6:"June",7:"July",8:"August",9:"September",10:"Ortobor",11:"November",12:"December"}
	Q2 := months[1:10]
	summer := months[6:9]
	for _,v := range Q2{
		for _,s := range summer   {
			if s == v {
				fmt.Println(s)
			}
		}
	}

}

如果slice的引用超过被引用对象的容量,即caps(s),那么会导致程序宕机,slice引用超出被引用对象的长度,即len(s),那么最终slice会比原来的slice长。
在这里插入图片描述
这幅图很直观的表现出来了len cap。
接下来我们说一说字符串与slice的区别
答:虽然它们都写做x[m:n],并且返回原始字节的一个子序列,同时它们的底层引用方式也是相同的,所以两个操作都消耗常量时间。区别在于:如果x是字符串,那么x[m:n]返回的是一个字符串,如果是slice返回的结果是字节slice

reverse函数

func main(){
	a := [...]int{1,2,3,4,5,6}
	reverse(a)
	fmt.Println(a)
}
func reverse(a []int){
	for(i,j := 0,len(a)-1;i<j;i,j = i+1,j-1){
		s[i],s[j] = s[j],s[i]
	}
}

将一个slice左移n个元素的简单方法是连续调用reverse函数三次。第一次反转前n个元素,第二次反转剩下的元素,最后对整个slice再做一次反转

	a:=[]int{0,1,2,3,4,5}
	reverse(a[:2])
	reverse(a[2:])
	reverse(a)
	fmt.Println(a)

数组访问必须是带上后面的括号,slice可以直接用变量代替

slice字面量看上去和数组字面量很像,都是用括号括起来的一个元素序列,但slice没有指定长度,就是这种隐式的区别代表了数组和slice,和数组不同的是,slice无法比较,因此不能用==来测试两个slice是否拥有相同的元素。标准库里面提供了高度优化的函数bytes.Equal来比较两个字节slice.但是对于其他类型slice,需要我们自己手写函数来比较。
slice的初始值是nil
如果检查slice是否为空,可以使用len(s) = = 0,而不是slice = nil,在slice != nil的情况下,slice也可能是空

内置mak可以创建一个指定元素类型,长度和容量的skuce

make([]T,len)
make([]T,len,cap)
package main

import "fmt"

func main() {
	var a = make([]string,2,3)
	a = []string{"1","2","3","4","5","6","7"}
	fmt.Println(a[0:5])
	fmt.Println(cap(a[0:5]))
	fmt.Println(len(a[0:5]))
}

#gosetup
[1 2 3 4 5]
7
5

Process finished with exit code 0

生成的结果cap是这个slice的最大容量,len代表当前筛选的slice的长度,当len长度扩展到cap以后就无法再扩展。

append函数
内置函数append用来将元素追加到slice后面

package main

import "fmt"

func main() {
	var runes []rune
	for _,r := range "Hello world 这个世界"{
		runes = append(runes,r)
	}
	fmt.Println(runes)
	fmt.Printf("%q/n",runes)
}

输出结果:

[72 101 108 108 111 32 119 111 114 108 100 32 36825 20010 19990 30028]
['H' 'e' 'l' 'l' 'o' ' ' 'w' 'o' 'r' 'l' 'd' ' ' '这' '个' '世' '界']/n
Process finished with exit code 0

append函数 append(被插入的slice,遍历的元素)

package main

import "fmt"

func main() {
	z := appendInt(make([]int,6,6),7)
	fmt.Println(z)
	fmt.Println(cap(z))
}
func appendInt(x []int,y int)[]int{
		var z []int
		zlen := len(x) + 1
		if zlen <= cap(x){
			z = x[:zlen]
		}else{
			zcap := zlen
			if(zcap < 2 * len(x)){
				zcap = 2 * len(x)
			}
			z = make([]int,zlen,zcap)
		}
		z[len(x)] = y
		return z
}

这段代码的意思,就是输入进如果len+1大于cap就将cap扩大原来的len的两倍,每一次的appendInt调用都必须检查slice是否仍有足够的容量来存储新的元素,如果可以容纳就继续增长,如果不能容纳必须创建新的cap slice,然后再执行上面的操作。
内置的copy函数,copy函数为两个相同类型元素的slice复制元素到目标slice中去,第一个参数是目标slice,第二参数是源slice。不同的slice可能对应相同的底层数组,甚至存在元素重叠

package main

import "fmt"

func main() {
	var a = make([]int,2,3)
	var b = make([]int,3,4)
	a = []int {1,2,3,4,5,6}
	b = []int {4,5,6,7}
	copy(b,a)
	fmt.Println(b)

}

copy函数的用法,当b设置cap为4时候,无论源程序有多少个数字,目标程序b只取前4个

package main

import "fmt"

func main() {
	var a = make([]int,2,3)
	var b = make([]int,3,4)
	a = []int {1,2,3,4,5,6}
	b = []int {4,5,6,7}
	copy(b,a)
	ints := append(b, 4, 5, 6, 7, 8)
	fmt.Println(ints)

}

slice就地修改

package main

import "fmt"

func main() {
	list := make([]int,2,3)
	list = []int{1,2,3}
	fmt.Println(list[:2])
	data := []string{"one","","three"}
	fmt.Println(nonempty(data))
	fmt.Println(numenmpty2(data))
}
func nonempty(strings []string)[]string  {
	i:=0
	for _,s := range strings{
		if s != ""{
			strings[i] = s
			i++
		}
	}
	return strings[:i]
}
func numenmpty2(strings []string) []string{
	out := strings[:0]
	for _,s := range strings{
		if s !=""{
			out = append(out,s)
		}
	}
	return out
}

将slice遍历后重新赋值,这也是修改slice的一种方法

package main

import "fmt"

func main() {
	list := make([]int,2,3)
	list = []int{1,2,3}
	fmt.Println(list[:2])
	data := []string{"one","","three"}
	fmt.Println(nonempty(data))
	fmt.Println(numenmpty2(data))
}
func nonempty(strings []string)[]string  {
	i:=0
	for _,s := range strings{
		if s != ""{
			strings[i] = s
			i++
		}
	}
	return strings[:i]
}
func numenmpty2(strings []string) []string{
	out := strings[:0]
	for _,s := range strings{
		if s !=""{
			out = append(out,s)
		}
	}
	return out
}

删除slice中的某个元素,大体思路是将删除的数据后面遍历出来,还要删除后一位数据遍历出来,使用copy函数,将删除后一位的数据覆盖删除的数据,就能完美将删除的数据覆盖掉

package main

import "fmt"

func remove(slice []int,i int)[] int{
	copy(slice[i:],slice[i+1:])
	return slice[:len(slice)-1]
}
func main() {
	s :=[]int{5,6,7,8,9}
	fmt.Println(remove(s,2))

}

map
学习map,我们要了解什么是散列表
散列表的介绍
在GO语言中map就是散列表的引用,map的类型是map[K]V,其中k和v是字典的键和值对应的数据类型。map所有键具有相同的数据类型,同时所有值也拥有相同类型,但是键和值的类型不一定相等
map就相当于python里面的字典

1.map元素不是一个变量,我无法获取他的地址,还有一个原因是map的增长会可能导致已有元素更改,,重新分配新的存储位置,这样可能获取地址无效

2.循环输出键和名字

package main

import "fmt"

func main() {
	age := map[string]int{
		"alice" :31,
		"charlie":34,
	}
	age["alice"] = 32
	age["charlie"] = 34

	for name,ages := range age{
		fmt.Println(name)
		fmt.Println(ages)
	}

}

使用sort对于string进行排序

package main

import (
	"fmt"
	"sort"
)

func main() {
	age := map[string]int{
		"alice" :31,
		"charlie":34,
	}
	age["alice"] = 32
	age["charlie"] = 34
	var name []string
	for names := range age{
		name = append(name,names)
	}
	sort.Strings(name)
	for _,named := range name{
		fmt.Println(named)
	}
}

3.如果访问map中不存在的元素,map会给这个元素为0,但是如果你凭空给map一个不存在键的值,就是出错
判断map中键存在与否

	list,ok := age["bob"]
	if !ok{
		fmt.Println("不存在")
	}else{
		fmt.Println(list)

4.map与slice一样都不能比较

结构体
结构体是将0个或多个任意类型的命名变量组合在一起的聚合数据类型,每个变量叫做结构体的成员

package main

import (
	"fmt"
	"time"
)

type Employee struct {
	ID int
	Name string
	Address string
	DoB time.Time
	Position string
	Salaray int
	ManagerID int
}

func main() {
	var dilbert Employee
	dilbert.Name = "测试"
	fmt.Println(dilbert.Name)
}

结构体字面量

package main

import "fmt"

type Point struct {
	s,v int
}
func main() {
	p:=&Point{1,2}
	fmt.Println(*p)
	q := new(Point)
	*q = Point{2,3}
	fmt.Println(*q)
}

结构体的比较

如果结构体的所有成员都是可以比较的,则这个结构体就可以比较

package main

import "fmt"

func main() {
	type Point struct {
		X,Y int
	}
	p := Point{1,2}
	q := Point{2,1}
	fmt.Println(p.Y == q.X)
	fmt.Println(p == q)
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值