Go基础语法

数组

数组是具有相同唯一类型的一组以编号且长度固定的数据项序列。类型可以是任意基本类型或者自定义类型。

数组一旦被定义后,大小不能被改变

func main() {
//定义一个数组
var nums [4]int //数组的下标从0开始
nums[0] = 1
nums[1] = 2
nums[2] = 3
nums[3] = 4 fmt.Printf("%T\n", nums)
//通过下标获取数组元素
fmt.Println(nums[0])
fmt.Println(nums[3]) //获取数组的长度
fmt.Println(len(nums))
//获取数组的容量
fmt.Println(cap(nums))
//数组的大小固定 所以长度和容量是相同的 }

数组初始化

func main() {
//常规的初始化
var arr1 = [4]int{1, 2, 3, 4}
fmt.Println(arr1) //快速定义数组
arr2 := [4]int{5, 6, 7, 8}
fmt.Println(arr2) //在不确定数组有多大下 可以是使用...定义长度
//编译器会根据传入的元素推断数据的长度
arr3 := [...]int{2, 3, 12, 3, 67, 4} //数组是可以有重复元素存在呦
fmt.Println(arr3)
fmt.Println(len(arr3))
fmt.Println(cap(arr3)) //初始化时也可以根据下标指定位置赋值
arr4 := [4]int{1: 34, 0: 100, 3: 45}
fmt.Println(arr4)
}

数组的遍历

func main() {
var arr = [5]int{1, 2, 3, 4, 5} for i := 0; i < len(arr); i++ {
fmt.Println(arr[i]) } //i下标 v元素值
for i, v := range arr {
fmt.Println(i, v)
}
}

数组是值传递类型

func main() {
num := 10
fmt.Printf("%T\n", num) arr1 := [5]int{1, 2, 3, 4, 5}
fmt.Printf("%T\n", arr1) arr2 := [3]string{"ni", "hao"}
fmt.Printf("%T\n", arr2)
fmt.Println(arr2) //数组是值传递类型
num2 := num //将num的值赋予ynum2
fmt.Println(num, num2) //10 10
num2 = 100 //改变num2的值
fmt.Println(num, num2) //10 100 num的值未改变 说明是值传递 arr3 := arr1
fmt.Println(arr1) //1 2 3 4 5
fmt.Println(arr3) //1 2 3 4 5
arr3[0] = 100 //改变arr3 第一个元素的值
//arr3只是arr1的拷贝 arr3的改变不会影响arr1
fmt.Println(arr1) //1 2 3 4 5 //没有被改变
fmt.Println(arr3) //100 2 3 4 5 }

数组的排序

func main() {

   /*
一堆书 34 12 4 1 88 按照相邻两个比较 得出 从大到小排序
1、34 12 4 88 1 4
2、34 12 88 4 1 3
3、34 88 12 4 1 2
4、88 34 12 4 1 1
ps:总共比较了4轮 同理34 12 4 1 88 从小到大
1、12 4 1 34 88
2、4 1 12 34 88
3、1 4 12 34 88 */ arr := [...]int{34, 12, 4, 1, 88}
sort(arr) } func sort(arr [5]int) {
for i := 1; i < len(arr); i++ {
for j := 0; j < len(arr)-i; j++ {
if arr[j] < arr[j+1] {
arr[j], arr[j+1] = arr[j+1], arr[j]
}
}
fmt.Println(arr)
}
}

多维数组

func main() {
var name [2][2]int
name[0][0] = 1
fmt.Println(name) var arrs = [3][4]int{
{1, 2, 3, 4},
{5, 6, 7, 8},
{9, 10, 11, 12},
} fmt.Println(arrs) //二维数据遍历
for i := 0; i < len(arrs); i++ {
for j := 0; j < len(arrs[i]); j++ {
fmt.Printf("%d ", arrs[i][j])
}
fmt.Println()
} for _, v := range arrs {
//fmt.Println(i, v)
for _, v2 := range v {
fmt.Println(v2)
}
}
}

切片

  • 切片的长度是不固定的
  • 可以追加元素,容量也会随之增大
  • 切片本身是没有数据的,都是对现有数据的引用
  • 所以切片是引用传递
func main() {
//数组 类型是 [5]int的长度一旦被确定就不可改变
var arr = [5]int{1, 2, 3}
fmt.Printf("%T\n", arr)
fmt.Println(arr) //定义一个切片 类型是[]int,他的长度是可变的 默认值为空[] 空的关键子是nil
var s1 []int
fmt.Printf("%T\n", s1)
fmt.Println(s1)
if s1 == nil {
fmt.Println("切片为空")
} var s2 = []int{1, 2, 5}
fmt.Println(s2)
//所以区分切片与数组的类型在于 [] 数据类型 中括号是否为空 //下面测试一下切片的传递类型
fmt.Println("==========================")
fmt.Println("s2的元素值:", s2) //1 2 5
s3 := s2
s3[1] = 4
fmt.Println("s2的元素值:", s2) //1 4 5
fmt.Println("s3的元素值:", s3) //1 4 5 //这里可以发现只改变了s3的元素值,但s2也随之改变 说明 s2与s3指向的是同一个地址 切片是引用传递
}

使用make创建切片

/*
使用make函数创建切盼
语法:make([]T,length,capacity) (类型,长度,容量)
长度是当前有多少个元素,容量是当前最大能够容纳多少元素
*/ func main() {
s1 := make([]int, 5, 10)
fmt.Println(s1)
fmt.Println("s1的长度:", len(s1)) //长度5
fmt.Println("s1的容量:", cap(s1)) //容量10
s1[1] = 100
s1[9] = 900 //这里会报错 虽然最大容量是10 但还是只能操作5个
fmt.Println(s1)
}
  • 实际生效的还是长度,可操作的元素也在长度中

切片扩容

  • 通过是append可以扩容切片
  • 在append中可以使用 切片... 展开切片相当于 取出所有的元素的缩写
s2 := make([]int, 0, 5)
//s2[0]=1//长度为0 无法操作
fmt.Println(s2)
//使用append扩容
s2 = append(s2, 1, 2)
fmt.Println(s2)
//如果追加的元素个数超出容量,那么切片就会自动扩容
s2 = append(s2, 3, 4, 5, 6, 7)
fmt.Println(s2, cap(s2)) //容量10 s3 := []int{6, 6, 6, 6, 6, 6}
s2 = append(s2, s3...) //在append 中使用”切片...“就可以吧元素都取出来
fmt.Println(s2, cap(s2)) //容量20 fmt.Println("for循环遍历s2")
for i := 0; i < len(s2); i++ {
fmt.Printf("%d ", s2[i])
} fmt.Println("forr遍历s2")
for i, v := range s2 {
fmt.Printf("%d:%d\n", i, v)
}
  • 切片底层其实是引用了数组
  • 每一次扩容,引用的地址会随之变化也就是说底层重新创建了一个数组,新的数组copy了原来数组的元素,切片的引用也会指向新数组
  • 每次扩容超出了原先切片的容量 容量就是2倍增长
func main() {

   s1 := []int{1, 2, 3}
fmt.Printf("容量:%d 长度:%d\n", cap(s1), len(s1))
fmt.Printf("地址:%p\n", s1) //地址:0xc0000aa078 s1 = append(s1, 4, 5)
fmt.Printf("容量:%d 长度:%d\n", cap(s1), len(s1))
fmt.Printf("地址:%p\n", s1) //地址:0xc0000c8030 s1 = append(s1, 6)
fmt.Printf("容量:%d 长度:%d\n", cap(s1), len(s1))
fmt.Printf("地址:%p\n", s1) //地址:0xc0000c8030 s1 = append(s1, 7, 8)
fmt.Printf("容量:%d 长度:%d\n", cap(s1), len(s1))
fmt.Printf("地址:%p\n", s1) //地址:0xc000086060 }

经常会见到: p . p , &p 三个符号

p是一个指针变量的名字,表示此指针变量指向的内存地址,如果使用%p来输出的话,它将是一个16进制数。而
p表示此指针指向的内存地址中存放的内容,一般是一个和指针类型一致的变量或者常量。

而我们知道,&是取地址运算符,&p就是取指针p的地址。等会,怎么又来了个地址,它到底和p有什么区别?区别在于,指针p同时也是个变量,既然是变量,编译器肯定要为其分配内存地址,就像程序中定义了一个int型的变量i,编译器要为其分配一块内存空间一样。而&p就表示编译器为变量p分配的内存地址,而因为p是一个指针变量,这种特殊的身份注定了它要指向另外一个内存地址,程序员按照程序的需要让它指向一个内存地址,这个它指向的内存地址就用p表示。而且,p指向的地址中的内容就用*p表示

通过数组创建切片

func main() {

   arr := [6]int{1, 2, 3, 4, 5, 6}
fmt.Println(arr)
//通过数组创建切片
//arr[start:end] 包含start 但不包含end
s1 := arr[:5] //下标0-4
fmt.Println(s1)
s2 := arr[2:4] //下标2-3
fmt.Println(s2)
s3 := arr[0:2] //下标0-1
fmt.Println(s3)
s4 := arr[:] //全部
fmt.Println(s4)
}

切片是引用传递类型

func main() {
s1 := []int{1, 2, 3, 4}
s2 := s1
fmt.Println(s1, s2)
s2[0] = 100
fmt.Println(s1, s2)
fmt.Printf("%p\n", s1)
fmt.Printf("%p\n", s2)
}

深拷贝与浅拷贝

深拷贝就是 将数值完全拷贝一份传入 等同值传递

浅拷贝 将引用地址拷贝 等同引用传递

func main() {
s1 := []int{1, 2, 3, 4}
s2 := make([]int, 0, 0)
//var s2 []int
//借助for循环实现深拷贝
for i := 0; i < len(s1); i++ {
s2 = append(s2, s1[i])
}
fmt.Println(s1, s2)
fmt.Printf("%p\n", s1)
fmt.Printf("%p\n", s2) //通过copy实现深拷贝
s3 := []int{5, 6}
copy(s1, s3) //copy(des,app) des是目标片 被修改的 app是修改的内容切片 不会动
fmt.Println(s1, s3)
fmt.Printf("%p\n", s1)
fmt.Printf("%p\n", s3) }

Map

  • 是一种无序的键值对集合
  • 可以通过key来快速检索数据
  • key相当于索引,value就是key指向的值
  • 是引用类型

map的初始化

func main() {
//map类型的定义,map[key]value
var map1 map[int]string //没有内容 是nil 还未被创建
var map2 = make(map[int]string) //通过make方式是被创建的 有内容是map[]
var map3 = map[string]int{"GO": 100, "JAVO": 90} if map1 == nil {
fmt.Println("win")
}
fmt.Println(map1)
if map2 == nil {
fmt.Println("win")
}
fmt.Println(map2)
if map3 == nil {
fmt.Println("win")
}
fmt.Println(map3) }
  • map中的key不可重复,添加重复的map是 新的value会将老的value覆盖

map的使用

func main() {
//创建map
var map1 map[int]string //这里只是声明有map1这个变量的存在并没有为其分配值空间
map1 = make(map[int]string) //需要通过make来创建map[]
map1[1] = "GO"
map1[2] = "JAVA"
map1[3] = "PYTHON"
fmt.Println(map1) //获取map中的数据
fmt.Println(map1[1]) //根据key值获取value值
fmt.Println(map1[4]) //key不存在 则会获取默认的零值 ”“ //可以通过map的一些属性值ok-idiom判断key是否存在
s, ok := map1[1]
if ok {
fmt.Println("key值存在,value", s)
} else {
fmt.Println("key值不存在,value", s)
} //修改map的value
map1[1] = "GoLan"
fmt.Println(map1) //删除数据
delete(map1, 1)
fmt.Println(map1) fmt.Println(len(map1))
map1[1] = "GO"
fmt.Println(map1)
fmt.Println(len(map1))
//key存在就是修改,不存在就是添加 }

map的遍历

func main() {
var map1 = map[int]string{100: "go", 90: "java", 80: "python"}
for i := range map1 {
fmt.Println(i, map1[i])
}
for i, v := range map1 {
fmt.Println(i, v)
} //引用传递哦
map2 := map1
map2[100] = "GOLAN"
fmt.Println(map1)
fmt.Println(map2)
}
/*
需求:
创建map来存储人的name、age、sex、addr信息
每个map存以一个人的信息
通过切片存入map
再按照标准name age sex addr顺序打印输出
*/ func main() {
var info map[string]string
info = make(map[string]string)
info["name"] = "xue"
info["age"] = "18"
info["sex"] = "nan"
info["addr"] = "china" info2 := make(map[string]string)
info2["name"] = "zhangsan"
info2["age"] = "20"
info2["sex"] = "nan"
info2["addr"] = "hangzhou" info3 := map[string]string{"name": "lisi", "age": "24", "sex": "nan", "addr": "sichuan"} //fmt.Println(info)
//fmt.Println(info2)
//fmt.Println(info3) infoData := make([]map[string]string, 0, 3)
infoData = append(infoData, info)
infoData = append(infoData, info2)
infoData = append(infoData, info3) for _, v := range infoData {
fmt.Printf("name:%s\n", v["name"])
fmt.Printf("age:%s\n", v["age"])
fmt.Printf("sex:%s\n", v["sex"])
fmt.Printf("addr:%s\n", v["addr"])
fmt.Println()
}
}

练习

/*
需求:
创建map来存储人的name、age、sex、addr信息
每个map存以一个人的信息
通过切片存入map
再按照标准name age sex addr顺序打印输出
*/ func main() {
var info map[string]string
info = make(map[string]string)
info["name"] = "xue"
info["age"] = "18"
info["sex"] = "nan"
info["addr"] = "china" info2 := make(map[string]string)
info2["name"] = "zhangsan"
info2["age"] = "20"
info2["sex"] = "nan"
info2["addr"] = "hangzhou" info3 := map[string]string{"name": "lisi", "age": "24", "sex": "nan", "addr": "sichuan"} //fmt.Println(info)
//fmt.Println(info2)
//fmt.Println(info3) infoData := make([]map[string]string, 0, 3)
infoData = append(infoData, info)
infoData = append(infoData, info2)
infoData = append(infoData, info3) for _, v := range infoData {
fmt.Printf("name:%s\n", v["name"])
fmt.Printf("age:%s\n", v["age"])
fmt.Printf("sex:%s\n", v["sex"])
fmt.Printf("addr:%s\n", v["addr"])
fmt.Println()
}
}

Go_day03的更多相关文章

随机推荐

  1. min-max 容斥简记

    min-max 容斥实际上就是这么个式子: \[\max(S_k) = \sum\limits_{T\subseteq S} (-1)^{|T|-k}\dbinom{|T|-1}{k-1}\min(T ...

  2. hdfs操作——hdfs的shell命令和hdfs的JavaAPI操作

    hdfs解决hadoop海量数据的存储. shell 命令(所有hadoop fs 可由 hdfs dfs代替) (1) 在hdfs上创建目录 hadoop fs -mkdir 目录名 (2) 本地文 ...

  3. Pytest 多进程并发执行

    在用例执行的过程中,想要用多进程并发执行测试用例,如何实现呢,其实很简单,pytest有对应的模块,安装方式. 安装 pip install pytest-xdist 使用 pytest test_d ...

  4. ie8 不支持 trim方法

    那就自己写一个trim()  String.prototype.trim = function() {                 return this.replace(/(^\s*)|(\s* ...

  5. python起航之路 Day1

    一.Python安装 windows 1.下载安装包 https://www.python.org/downloads/2.安装 默认安装路径:C:\python273.配置环境变量 [右键计算机]- ...

  6. 类继承(c++ primer plus)课后习题

    第一题: // base class class Cd { // represents a CD disk private: char performers[50]; char label[20]; ...

  7. Python GUI编程之Tkinter

    GUI编程Tkinter Python 提供了多个图形开发界面的库,几个常用 Python GUI 库如下: Tkinter: Tkinter 模块(Tk 接口)是 Python 的标准 Tk GUI ...

  8. spring security添加接口白名单

    在项目中遇到的问题是要将某个接口设为白名单,无需验证即可被用户使用. 解决方法: 在nacos配置文件中ignore whites(不校验白名单)中添加对应接口,无gateway前缀即可,添加立即生效 ...

  9. 微信小程序ECharts通过调用api接口实现图表的数据可视化

    小程序ECharts使用接口调入数据 首先附上js文件链接:axios.js 提取码:AxIo 将此放到小程序目录下的utils文件夹下 在已经完成图表的js文件中完成以下修改: ①引用axios.j ...

  10. 基于CMMI的软件工程第一章读书笔记

    基于CMMI的软件工程第一章读书笔记 软件作为产品,就如机械业以及一般的加工业一样,只有对产品的产生流程和角色分工及其相应的管理活动有一个成熟的模式,能"更快,更好,更便宜"地开发 ...