其他分享
首页 > 其他分享> > go_day02数组和切片

go_day02数组和切片

作者:互联网

数组长度是数组类型的一部分
数组的定义

//声明
var a1 [3]int
fmt.Print(a1)
//赋值,注意要加上长度和类型
a1 = [3]int{1, 2, 3}
//函数中的方法1
a2 := [3]int{1, 2, 3}
//函数中的方法2
a3 := [...]int{1, 3, 4}
//函数中的方法3,使用索引
a4 := [5]int{0: 1, 4: 5}
fmt.Print(a1, a2, a3, a4)
//[0 0 0][1 2 3] [1 2 3] [1 3 4] [1 0 0 0 5]

没别的,记得在数组赋值前给出数组的长度和类型

定义二维数组

var a [3]int = [3]int{1, 2, 3}
fmt.Print(a)
var b [3][2]int = [3][2]int{
	[2]int{1, 2},
	[2]int{3, 4},
	[2]int{5, 6},
}
fmt.Print(b)
//[1 2 3][[1 2] [3 4] [5 6]]

二维数组在初始化时长度和类型可以不写

var b [3][2]int = [3][2]int{
	{1, 2},
	{3, 4},
	{5, 6},
}
fmt.Print(b)

数组是值的形式,不是引用类型

// array数组练习题
//1.求数组[1,3,5,7,8]所有元素的和
//找出数组中和为指定值的两个元素的下标,如找出和为8的下标为(1,2),(0,3)
func main() {
	a := [...]int{1, 3, 5, 7, 8}
	ret := 0
	for _, v := range a {
		ret += v
	}
	fmt.Print(ret)
	s := 8
	for i := 0; i < len(a); i++ {
		for j := i + 1; j < len(a); j++ {
			if a[i]+a[j] == s {
				fmt.Printf("(%d %d)", i, j)
			}
		}
	}

切片 可变长度,前面的数组不可变长,就是将长度[]中的数字不写。。
切片是引用类型,都指向了一个底层的数组,它没有自己的值,相当于一个框在数组上进行框选.它框选的是连续的内存
image

声明切片且没有初始化时,切片==nil,为空(没有开辟内存空间。)
len求长度
cap求容量
切片的创建方式3种
1.和数组一样创建
2.由数组来创建(左闭右开)

s := []int{1, 2, 4, 5, 6, 7}
a := s[0:4]
fmt.Print(a)
\\ [1 2 4 5]
b := s[:3]
c := s[1:]
d := s[:]

切片指向了一个底层数组,即使使用第一种方法直接创建切片,它也是先创建了一个数组再返回切片。修改底层数组的值会直接修改切片的值
切片的长度就是它元素的长度
切片的容量就是底层数组从切片的第一个元素到最后一个元素的数量
3.通过make来创建

s1 := make([]int, 5, 10)
fmt.Printf("%v %d %d", s1, len(s1), cap(s1))

切片之间是不能比较的,我们不能使用==操作符来判断两个切片是否含有全部相等元素。 切片唯一合法的比较操作是和nil比较。 一个nil值的切片并没有底层数组,一个nil值的切片的长度和容量都是0。但是我们不能说一个长度和容量都是0的切片一定是nil
所以要判断一个切片是否是空的,要是用len(s) == 0来判断,不应该使用s == nil来判断。
也就是没有分配内存地址时为nil,如果分配了空数组则长度和容量为0

var s1 []int         //len(s1)=0;cap(s1)=0;s1==nil
s2 := []int{}        //len(s2)=0;cap(s2)=0;s2!=nil
s3 := make([]int, 0) //len(s3)=0;cap(s3)=0;s3!=nil
s1 := make([]int, 5, 10)
s2 := s1
fmt.Println(s1, s2)
s1[0] = 1
fmt.Println(s1, s2)
//[0 0 0 0 0] [0 0 0 0 0]
//[1 0 0 0 0] [1 0 0 0 0]

使用append来增加元素

s1 := []string{"beijing", "shanghai", "wuhan"}
fmt.Printf("s1=%v len(s1)=%d cap(s1)=%d\n", s1, len(s1), cap(s1))
// s1[3] = "suzhou" 错误写法,索引越界
// 调用append函数后需要用原来的切片变量接收返回值
s1 = append(s1, "suzhou") //append追加元素,原来的底层数组放不下是,GO底层会将底层数组换一个
fmt.Printf("s1=%v len(s1)=%d cap(s1)=%d\n", s1, len(s1), cap(s1))

注意append需要传值给原切片
append不需要先给切片创建初始值后再使用

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
		}
	}
}

从上面的代码可以看出以下内容:

  1. 首先判断,如果新申请容量(cap)大于2倍的旧容量(old.cap),最终容量(newcap)就是新申请的容量(cap)。
  2. 否则判断,如果旧切片的长度小于1024,则最终容量(newcap)就是旧容量(old.cap)的两倍,即(newcap=doublecap),
  3. 否则判断,如果旧切片长度大于等于1024,则最终容量(newcap)从旧容量(old.cap)开始循环增加原来的1/4,即(newcap=old.cap,for {newcap += newcap/4})直到最终容量(newcap)大于等于新申请的容量(cap),即(newcap >= cap)
  4. 如果最终容量(cap)计算值溢出,则最终容量(cap)就是新申请容量(cap)

需要注意的是,切片扩容还会根据切片中元素的类型不同而做不同的处理,比如int和string类型的处理方式就不一样。

s1 := []string{"beijing", "shanghai", "wuhan"}
fmt.Printf("s1=%v len(s1)=%d cap(s1)=%d\n", s1, len(s1), cap(s1))
// s1[3] = "suzhou" 错误写法,索引越界
// 调用append函数后需要用原来的切片变量接收返回值
s1 = append(s1, "suzhou") //append追加元素,原来的底层数组放不下是,GO底层会将底层数组换一个
fmt.Printf("s1=%v len(s1)=%d cap(s1)=%d\n", s1, len(s1), cap(s1))
s2 := make([]string, 3)
s2[0] = "nanjing"
s1 = append(s1, s2...)
fmt.Printf("s1=%v len(s1)=%d cap(s1)=%d\n", s1, len(s1), cap(s1))

使用另一个切片来append时,需要将那个切片使用...来进行拆开

s1 := []string{"1", "2", "3"}
s2 := s1
s3 := make([]string, 3, 3)
copy(s3, s2)
s1[1] = "7"
fmt.Println(s1, s2, s3)
//[1 7 3] [1 7 3] [1 2 3]

使用copy时注意需要注意前面是目的切片位置,并且目的位置需要将保证长度能够容纳原切片的大小

s1 := []string{"1", "2", "3"}
// 将s1中索引为1的元素删除
s1 = append(s1[:1], s1[2:]...)
fmt.Println(s1)

注意,这里的切片通过append也修改了底层的数组

s := [...]int{1, 2, 3}
s1 := s[:]
// 将s1中索引为1的元素删除
s1 = append(s1[:1], s1[2:]...)
fmt.Println(s1)
fmt.Println(s)
// [1 3]
// [1 3 3]

两个作业:
1.make会给出元素

func main() {
	var a = make([]int, 5, 10)
	for i := 0; i < 10; i++ {
		a = append(a, i)
	}
	fmt.Println(a)
}
//[0 0 0 0 0 0 1 2 3 4 5 6 7 8 9]

2.使用sort排序切片

func main() {
	var a = [...]int{11, 2, 13, 4}
	sort.Ints(a[:])
	fmt.Printf("%v\n", a)
}
//[2 4 11 13]

标签:newcap,int,day02,s1,cap,切片,go,fmt
来源: https://www.cnblogs.com/ydssx7/p/15814848.html