GO语言系列- 高级数据类型之数组、切片、map
分类:
IT文章
•
2022-05-30 21:06:15
一、数组和切片
数组
- 1. 数组:是同一种数据类型的固定长度的序列。
- 2. 数组定义:var a [len]int,比如:var a[5]int,一旦定义,长度不能变
- 3. 长度是数组类型的一部分,因此,var a[5] int和var a[10]int是不同的类型
- 4. 数组可以通过下标进行访问,下标是从0开始,最后一个元素下标是:len-1
for i := 0; i < len(a); i++ {
}
for index, v := range a {
}
- 5. 访问越界,如果下标在数组合法范围之外,则触发访问越界,会panic
- 6. 数组是值类型,因此改变副本的值,不会改变本身的值
package main
import "fmt"
func test1() {
var a [10]int
a[0] = 10
a[9] = 100
fmt.Println(a)
for i := 0; i < len(a); i++ {
fmt.Println(a[i])
}
for index, val := range a {
fmt.Printf("a[%d]=%d
", index, val)
}
}
func test2() {
var a [10]int
b := a
b[0] = 100
fmt.Println(a)
}
func test3(arr *[5]int) {
(*arr)[0] = 1000
}
func main() {
test1()
test2()
var a [5]int
test3(&a)
fmt.Println(a)
}
/*
[10 0 0 0 0 0 0 0 0 100]
10
0
0
0
0
0
0
0
0
100
a[0]=10
a[1]=0
a[2]=0
a[3]=0
a[4]=0
a[5]=0
a[6]=0
a[7]=0
a[8]=0
a[9]=100
[0 0 0 0 0 0 0 0 0 0]
[1000 0 0 0 0]
*/
数组示例一
数组初始化
a. var age0 [5]int = [5]int{1,2,3}
b. var age1 = [5]int{1,2,3,4,5}
c. var age2 = […]int{1,2,3,4,5,6}
d. var str = [5]string{3:”hello world”, 4:”tom”}
多维数组
a. var age [5][3]int
b. var f [2][3]int = [...][3]int{{1, 2, 3}, {7, 8, 9}}
多维数组遍历
package main
import (
"fmt"
)
func main() {
var f [2][3]int = [...][3]int{{1, 2, 3}, {7, 8, 9}}
for k1, v1 := range f {
for k2, v2 := range v1 {
fmt.Printf("(%d,%d)=%d ", k1, k2, v2)
}
fmt.Println()
}
}
数组示例
package main
import (
"fmt"
)
func fab(n int) {
var a []int
a = make([]int, n)
a[0] = 1
a[1] = 1
for i := 2; i < n; i++ {
a[i] = a[i-1] + a[i-2]
}
for _, v := range a {
fmt.Println(v)
}
}
func testArray() {
var a [5]int = [5]int{1, 2, 3, 4, 5}
var a1 = [5]int{1, 2, 3, 4, 5}
var a2 = [...]int{38, 283, 48, 38, 348, 387, 484}
var a3 = [...]int{1: 100, 3: 200}
var a4 = [...]string{1: "hello", 3: "world"}
fmt.Println(a)
fmt.Println(a1)
fmt.Println(a2)
fmt.Println(a3)
fmt.Println(a4)
/*
[1 2 3 4 5]
[1 2 3 4 5]
[38 283 48 38 348 387 484]
[0 100 0 200]
[ hello world]
*/
}
func testArray2() {
var a [2][5]int = [...][5]int{{1, 2, 3, 4, 5}, {6, 7, 8, 9, 10}}
for row, v := range a {
for col, v1 := range v {
fmt.Printf("(%d,%d)=%d ", row, col, v1)
}
fmt.Println()
}
}
func main() {
fab(10)
testArray()
testArray2()
}
数组示例二
切片
1. 切片相关概念
- 1. 切片:切片是数组的一个引用,因此切片是引用类型
- 2. 切片的长度可以改变,因此,切片是一个可变的数组
- 3. 切片遍历方式和数组一样,可以用len()求长度
- 4. cap可以求出slice最大的容量,0 <= len(slice) <= (array),其中array是slice引用的数组
- 5. 切片的定义:var 变量名 []类型,比如 var str []string var arr []int
2. 切片的相关语法
- 1. 切片初始化:var slice []int = arr[start:end] 包含start到end之间的元素,但不包含end
- 2. Var slice []int = arr[0:end]可以简写为 var slice []int=arr[:end]
- 3. Var slice []int = arr[start:len(arr)] 可以简写为 var slice[]int = arr[start:]
- 4. Var slice []int = arr[0, len(arr)] 可以简写为 var slice[]int = arr[:]
- 5. 如果要切片最后一个元素去掉,可以这么写: Slice = slice[:len(slice)-1]
3. 切片的内存布局
4. 通过make来创建切片
var slice []type = make([]type, len)
slice := make([]type, len)
slice := make([]type, len, cap)
5. 用append内置函数操作切片
slice = append(slice, 10)
var a = []int{1,2,3}
var b = []int{4,5,6}
a = append(a, b…)
6. For range 遍历切片
for index, val := range slice {
}
7. 切片resize
var a = []int {1,3,4,5}
b := a[1:2]
b = b[0:3]
8. 切片拷贝
s1 := []int{1,2,3,4,5}
s2 := make([]int, 10)
copy(s2, s1)
s3 := []int{1,2,3}
s3 = append(s3, s2…)
s3 = append(s3, 4,5,6)
9. string与slice
string底层就是一个byte的数组,因此,也可以进行切片操作
str := “hello world”
s1 := str[0:5]
fmt.Println(s1)
s2 := str[5:]
fmt.Println(s2)
10. string的底层布局
11. 如何改变string中的字符值?
string本身是不可变的,因此要改变string中字符,需要如下操作:
str := “hello world”
s := []byte(str)
s[0] = ‘o’
str = string(s)
12. 排序和查找操作
排序操作主要都在 sort包中,导入就可以使用了
sort.Ints对整数进行排序, sort.Strings对字符串进行排序, sort.Float64s对
浮点数进行排序.
sort.SearchInts(a []int, b int) 从数组a中查找b,前提是a必须有序
sort.SearchFloats(a []float64, b float64) 从数组a中查找b,前提是a必须有序
sort.SearchStrings(a []string, b string) 从数组a中查找b,前提是a必须有序
13. 切片的扩容机制
可以通过查看$GOROOT/src/runtime/slice.go
源码,其中扩容相关代码如下:
newcap := old.cap
doublecap := newcap + newcap
if cap > doublecap {
newcap = cap
} else {
if old.len < 1024 {
newcap = doublecap
} else {
// Check 0 < newcap to detect overflow
// and prevent an infinite loop.
for 0 < newcap && newcap < cap {
newcap += newcap / 4
}
// Set newcap to the requested cap when
// the newcap calculation overflowed.
if newcap <= 0 {
newcap = cap
}
}
}
从上面的代码可以看出以下内容:
- 首先判断,如果新申请容量(cap)大于2倍的旧容量(old.cap),最终容量(newcap)就是新申请的容量(cap)。
- 否则判断,如果旧切片的长度小于1024,则最终容量(newcap)就是旧容量(old.cap)的两倍,即(newcap=doublecap),
- 否则判断,如果旧切片长度大于等于1024,则最终容量(newcap)从旧容量(old.cap)开始循环增加原来的1/4,即(newcap=old.cap,for {newcap += newcap/4})直到最终容量(newcap)大于等于新申请的容量(cap),即(newcap >= cap)
- 如果最终容量(cap)计算值溢出,则最终容量(cap)就是新申请容量(cap)。
需要注意的是,切片扩容还会根据切片中元素的类型不同而做不同的处理,比如int
和string
类型的处理方式就不一样。
示例
package main
import "fmt"
type slice struct {
ptr *[100]int
len int
cap int
}
func make1(s slice, cap int) slice {
s.ptr = new([100]int)
s.cap = cap
s.len = 0
return s
}
func testSlice() {
var slice []int
var arr [5]int = [...]int{1, 2, 3, 4, 5}
slice = arr[:]
fmt.Println(slice)
fmt.Println(arr[2:4]) // [3,4]
fmt.Println(arr[2:]) // [3,4,5]
fmt.Println(arr[0:1]) // [1]
fmt.Println(arr[:len(arr)-1])
}
func modify(s slice) {
s.ptr[1] = 1000
}
func testSlice2() {
var s1 slice
s1 = make1(s1, 10)
s1.ptr[0] = 100
modify(s1)
fmt.Println(s1.ptr)
}
func modify1(a []int) {
a[1] = 1000
}
func testSlice3() {
var b []int = []int{1, 2, 3, 4}
modify1(b)
fmt.Println(b)
}
func testSlcie4() {
var a = [10]int{1, 2, 3, 4}
b := a[1:5]
fmt.Printf("%p
", b) // 0xc000014238
fmt.Printf("%p
", &a[1]) // 0xc000014238
}
func main() {
// testSlice()
testSlice2()
testSlice3()
testSlcie4()
}
切片的用法示例一
package main
import "fmt"
func testSlice() {
var a [5]int = [...]int{1, 2, 3, 4, 5}
s := a[1:]
fmt.Println("a:", a)
s[1] = 100
fmt.Printf("s=%p a[1]=%p
", s, &a[1])
fmt.Println("before a:", a)
s = append(s, 10)
s = append(s, 10)
s = append(s, 10)
s = append(s, 10)
s = append(s, 10)
s[1] = 1000
fmt.Println("after a:", a)
fmt.Println(s)
fmt.Printf("s=%p a[1]=%p
", s, &a[1])
}
func testCopy() {
var a []int = []int{1, 2, 3, 4, 5}
b := make([]int, 10)
copy(b, a)
fmt.Println(b)
}
func testString() {
s := "hello world"
s1 := s[0:5]
s2 := s[6:]
fmt.Println(s1)
fmt.Println(s2)
}
func testModifyString() {
s := "我hello world"
s1 := []rune(s)
s1[0] = 200
s1[1] = 128
s1[2] = 256
str := string(s1)
fmt.Println(str)
}
func main() {
// testSlice()
testCopy()
testString()
testModifyString()
}
切片的用法示例二
package main
import (
"fmt"
"sort"
)
func testIntSort() {
var a = [...]int{1, 8, 43, 2, 456}
sort.Ints(a[:])
fmt.Println(a)
}
func testStrings() {
var a = [...]string{"abc", "efg", "b", "A", "eeee"}
sort.Strings(a[:])
fmt.Println(a)
}
func testFloat() {
var a = [...]float64{2.3, 0.8, 28.2, 392342.2, 0.6}
sort.Float64s(a[:])
fmt.Println(a)
}
func testIntSearch() {
var a = [...]int{1, 8, 43, 2, 456}
index := sort.SearchInts(a[:], 2)
fmt.Println(index)
}
func main() {
testIntSort()
testStrings()
testFloat()
testIntSearch()
}
切片的用法示例三
二、map数据结构
1.map简介
key-value的数据结构,又叫字典或关联数组
a.声明
var map1 map[keytype]valuetype
var a map[string]string
var a map[string]int
var a map[int]string
var a map[string]map[string]string
声明是不会分配内存的,初始化需要make
2. map相关操作
var a map[string]string = map[string]string{“hello”: “world”}
a = make(map[string]string, 10)
a[“hello”] = “world” // 插入和更新
Val, ok := a[“hello”] //查找
for k, v := range a { //遍历
fmt.Println(k,v)
}
delete(a, “hello”) // 删除
len(a) // 长度
3. map是引用类型
func modify(a map[string]int) {
a[“one”] = 134
}
4. slice of map
Items := make([]map[int][int], 5)
For I := 0; I < 5; i++ {
items[i] = make(map[int][int])
}
5. map排序
a. 先获取所有key,把key进行排序
b. 按照排序好的key,进行遍历
6. Map反转
- a. 初始化另外一个map,把key、value互换即可
示例
package main
import "fmt"
func trans(a map[string]map[string]string) {
for k, v := range a {
fmt.Println(k)
for k1, v1 := range v {
fmt.Println(" ", k1, v1)
}
}
}
func testMap() {
var a map[string]string = map[string]string{
"key": "value",
}
// a := make(map[string]string, 10)
a["abc"] = "efg"
a["abc1"] = "wew"
fmt.Println(a)
}
func testMap2() {
a := make(map[string]map[string]string, 100)
a["key1"] = make(map[string]string)
a["key1"]["key2"] = "val2"
a["key1"]["key3"] = "val3"
a["key1"]["key4"] = "val4"
a["key1"]["key5"] = "val5"
a["key1"]["key6"] = "val6"
fmt.Println(a)
}
func modify(a map[string]map[string]string) {
_, ok := a["zhangsan"]
if !ok {
a["zhangsan"] = make(map[string]string)
}
a["zhangsan"]["pwd"] = "123456"
a["zhangsan"]["nickname"] = "superman"
return
}
func testMap3() {
a := make(map[string]map[string]string, 100)
modify(a)
fmt.Println(a)
}
func testMap4() {
a := make(map[string]map[string]string, 100)
a["key1"] = make(map[string]string)
a["key1"]["key2"] = "val2"
a["key1"]["key3"] = "val3"
a["key1"]["key4"] = "val4"
a["key1"]["key5"] = "val5"
a["key2"] = make(map[string]string)
a["key2"]["key22"] = "val22"
a["key2"]["key23"] = "val23"
trans(a)
delete(a, "key1")
fmt.Println()
trans(a)
}
func testMap5() {
var a []map[int]int
a = make([]map[int]int, 5)
if a[0] == nil {
a[0] = make(map[int]int)
}
a[0][10] = 10
fmt.Println(a)
}
func main() {
testMap()
testMap2()
testMap3()
testMap4()
testMap5()
}
map示例
package main
import (
"fmt"
"sort"
)
func testMapSort() {
var a map[int]int
a = make(map[int]int, 5)
a[8] = 10
a[3] = 10
a[2] = 10
a[1] = 10
a[18] = 10
var keys []int
for k, _ := range a {
keys = append(keys, k)
// fmt.Println(k, v)
}
sort.Ints(keys)
for _, v := range keys {
fmt.Println(v, a[v])
}
}
func testMapSort2() {
var a map[string]int
var b map[int]string
a = make(map[string]int, 5)
b = make(map[int]string, 5)
a["8"] = 10
a["3"] = 11
a["2"] = 12
a["1"] = 13
a["18"] = 14
for k, v := range a {
b[v] = k
}
fmt.Println(b)
}
func main() {
testMapSort()
testMapSort2()
}
map示例2
补充:golang实现集合(set)
package set
import (
"bytes"
"fmt"
"sync"
)
type Set struct {
m map[interface{}]bool
sync.RWMutex
}
func New() *Set {
return &Set{m: make(map[interface{}]bool)}
}
func (self *Set) Add(e interface{}) bool {
self.Lock()
defer self.Unlock()
if self.m[e] {
return false
}
self.m[e] = true
return true
}
func (self *Set) Remove(e interface{}) bool {
self.Lock()
defer self.Unlock()
delete(self.m, e)
return true
}
func (self *Set) Clear() bool {
self.Lock()
defer self.Unlock()
self.m = make(map[interface{}]bool)
return true
}
func (self *Set) Contains(e interface{}) bool {
self.Lock()
defer self.Unlock()
//return self.m[e]
_, ok := self.m[e]
return ok
}
func (self *Set) IsEmpty() bool {
return self.Len() == 0
}
func (self *Set) Len() int {
self.Lock()
defer self.Unlock()
return len(self.m)
}
func (self *Set) Same(other *Set) bool {
if other == nil {
return false
}
if self.Len() != other.Len() {
return false
}
for k, _ := range other.m {
if !self.Contains(k) {
return false
}
}
return true
}
func (self *Set) Elements() interface{} {
self.Lock()
defer self.Unlock()
// for k := range self.m{
// snapshot = snapshot(snapshot, k)
// }
initialLen := self.Len()
actualLen := 0
snapshot := make([]interface{}, initialLen)
for k := range self.m {
if actualLen < initialLen {
snapshot[actualLen] = k
} else {
snapshot = append(snapshot, k)
}
actualLen++
}
if actualLen < initialLen {
snapshot = snapshot[:actualLen]
}
return snapshot
}
func (self *Set) String() string {
self.Lock()
defer self.Unlock()
var buf bytes.Buffer
buf.WriteString("Set{")
flag := true
for k := range self.m {
if flag {
flag = false
} else {
buf.WriteString(" ")
}
buf.WriteString(fmt.Sprintf("%v", k))
}
buf.WriteString("}")
return buf.String()
}
func (self *Set) IsSuperSet(other *Set) bool {
self.Lock()
defer self.Unlock()
if other == nil {
return false
}
selfLen := self.Len()
otherLen := other.Len()
if otherLen == 0 || selfLen == otherLen {
return false
}
if selfLen > 0 && otherLen == 0 {
return true
}
for v := range other.m {
if !self.Contains(v) {
return false
}
}
return true
}
//属于A或属于B的元素
func (self *Set) Union(other *Set) *Set {
self.Lock()
defer self.Unlock()
// if other == nil || other.Len() == 0{
// return self
// }
//
// for v := range other.m{
// self.Add(v)
// }
// return self
//不能改变集合A的范围
union := New()
for v := range self.m {
union.Add(v)
}
for v := range other.m {
union.Add(v)
}
return union
}
//属于A且属于B的元素
func (self *Set) Intersect(other *Set) *Set {
self.Lock()
defer self.Unlock()
if other == nil || other.Len() == 0 {
return New()
}
intsSet := New()
for v, _ := range other.m {
if self.Contains(v) {
intsSet.Add(v)
}
}
return intsSet
}
//属于A且不属于B的元素
func (self *Set) Difference(other *Set) *Set {
self.Lock()
defer self.Unlock()
diffSet := New()
if other == nil || other.Len() == 0 {
diffSet.Union(self)
} else {
for v := range self.m {
if !other.Contains(v) {
diffSet.Add(v)
}
}
}
return diffSet
}
//集合A与集合B中所有不属于A∩B的元素的集合
func (self *Set) SymmetricDifference(other *Set) *Set {
self.Lock()
defer self.Unlock()
//此时A∩B=∅,A中所有元素均不属于空集
// if other == nil || other.Len() == 0{
// return self
// }
// ints := self.Intersect(other)
// //此时A∩B=∅,A为空或B为空,B为空前面已经判断,此时B不能为空,即A为空
// if ints == nil || ints.Len() == 0 {
// return other
// }
//
// unionSet := self.Union(other)
// result := New()
// for v := range unionSet.m{
// if !ints.Contains(v){
// result.Add(v)
// }
// }
ints := self.Difference(other)
union := self.Union(other)
return union.Difference(ints)
}
package set
package main
import (
"fmt"
"go_dev/go_set/set"
)
func main() {
setTest()
}
func setTest() {
set1 := set.New()
set1.Add(1)
set1.Add("e2")
set1.Add(3)
set1.Add("e4")
fmt.Println("set1:", set1)
fmt.Printf("set1 Elements:%v
", set1.Elements())
set2 := set.New()
set2.Add(3)
set2.Add("e2")
set2.Add(5)
set2.Add("e6")
fmt.Println("set2:", set2)
fmt.Printf("set1 union set2:%v
", set1.Union(set2))
fmt.Printf("set1 intersect set2:%v
", set1.Intersect(set2))
fmt.Println(set1,set2)
fmt.Printf("set1 difference set2:%v
", set1.Difference(set2))
fmt.Printf("set1 SymmetricDifference set2:%v
", set1.SymmetricDifference(set2))
set1.Clear()
fmt.Println(set1)
}
main.go
三、包
1. golang中的包
2. 线程同步
a. import(“sync”)
b. 互斥锁, var mu sync.Mutex
c. 读写锁, var mu sync.RWMutex
package main
import (
"fmt"
"math/rand"
"sync"
"sync/atomic"
"time"
)
var rwLock *sync.RWMutex
func testLock() {
var a map[int]int
a = make(map[int]int, 5)
a[8] = 10
a[3] = 10
a[2] = 10
a[1] = 10
a[18] = 10
for i := 0; i < 2; i++ {
go func(b map[int]int) {
rwLock.RLock()
b[8] = rand.Intn(100)
rwLock.Unlock()
}(a)
}
rwLock.RLock()
fmt.Println(a)
rwLock.Unlock()
}
func testRWLock() {
// var rwLock myLocker = new(sync.RWMutex)
// var rwLock sync.RWMutex
// var rwLock sync.Mutex
var a map[int]int
a = make(map[int]int, 5)
var count int32
a[8] = 10
a[3] = 10
a[2] = 10
a[1] = 10
a[18] = 10
for i := 0; i < 2; i++ {
go func(b map[int]int) {
rwLock.Lock()
// lock.Lock()
b[8] = rand.Intn(100)
time.Sleep(time.Millisecond)
rwLock.Unlock()
// lock.Unlock()
}(a)
}
for i := 0; i < 100; i++ {
go func(b map[int]int) {
for {
rwLock.Lock()
time.Sleep(time.Millisecond)
// fmt.Println(a)
rwLock.Unlock()
atomic.AddInt32(&count, 1)
}
}(a)
}
time.Sleep(time.Second * 3)
fmt.Println(atomic.LoadInt32(&count))
}
func main() {
rwLock = new(sync.RWMutex)
// testLock()
testRWLock()
}
线程同步锁示例
3. go get安装第三方包
go get github.com/go-sql-driver/mysql
本节作业
-
1. 冒泡排序
-
2. 选择排序
-
3. 插入排序
-
4.快速排序
参考
package main
import "fmt"
// 冒泡排序:本质上是交换排序的一种
func bsort(a []int) {
for i := 0; i < len(a); i++ {
for j := 1; j < len(a)-i; j++ {
if a[j] < a[j-1] {
a[j], a[j-1] = a[j-1], a[j]
}
}
}
}
func main() {
b := [...]int{8, 7, 4, 5, 3, 2, 1}
bsort(b[:])
fmt.Println(b)
}
冒泡排序
package main
import "fmt"
// 选择排序
func ssort(a []int) {
for i := 0; i < len(a); i++ {
var min int = i
for j := i + 1; j < len(a); j++ {
if a[min] > a[j] {
min = j
}
}
if min != i {
a[i], a[min] = a[min], a[i]
}
}
}
func main() {
b := [...]int{8, 7, 4, 5, 3, 2, 1}
ssort(b[:])
fmt.Println(b)
}
选择排序
package main
import "fmt"
// 插入排序, 每次将一个数插入到有序序列当中合适的位置
func isort(a []int) {
for i := 1; i < len(a); i++ {
for j := i; j > 0; j-- {
if a[j] > a[j-1] {
break
}
a[j], a[j-1] = a[j-1], a[j]
}
}
}
func main() {
b := [...]int{8, 7, 4, 5, 3, 2, 1}
isort(b[:])
fmt.Println(b)
}
插入排序
package main
import "fmt"
// 快速排序, 一次排序确定一个元素的位置, 使左边的元素都比它小,右边的元素都比它大
func qsort(a []int, left, right int) {
if left >= right {
return
}
val := a[left]
// 确定val所在的位置
k := left
for i := left + 1; i <= right; i++ {
if a[i] < val {
a[k] = a[i]
a[i] = a[k+1]
k++
}
}
a[k] = val
qsort(a, left, k-1)
qsort(a, k+1, right)
}
func main() {
b := [...]int{8, 7, 4, 5, 3, 2, 1}
qsort(b[:], 0, len(b)-1)
fmt.Println(b)
}
快速排序