GO语言小锤硬磕十三、数组与切片

数组用来保存一组相同类型的数据,go语言数组也分一维数组和多维数组。

直接上代码看一下一维数组特性

package main
import "fmt"
func main(){
//1.定义数组         var 数组名称 [元素个数]数据类型
    var arr1 [2]int      //[0 0]定义就有为0的默认值
    var arr2 [3]bool     //[false false false]

//2.多种初始化方式
   //定义时完全初始化
    var arr3 [3]int = [3]int{1,3,5}    //[1 3 5]

   //定义时部分初始化  
    var arr4 [3]int = [3]int{8,9}      //[8 9 0]  

   //定义时指定元素初始化
    var arr5 [3]int = [3]int{0:8,2:9} //[8 0 9]
 
   //先定义再逐个初始化,访问数组通过  数组名称[索引]  的方式
    var arr6 [3]string
    arr6[0] = "ok"
    arr6[1] = "hello"
    arr6[2] = "world"
    
   //先定义再一次性初始化(与C语言数组不同)
    arr1 = [2]{1,2}    //[1 2]
    arr2 = [3]{true,true,false}  //[true true true]

//3.定义元素同时初始化,元素的个数可以省略,使用  ...  代替
    var arr7 = [...]int{1,3,5}    //[1 3 5]
    var arr8 = [...]int{6:5}    //[0 0 0 0 0 0 5]

//4.两种遍历数组的方式,for循环遍历,for...range循环遍历
    arr := [...]int{1,3,5}
    for i:=0; i<len(arr); i++{
        fmt.Println(i, arr[i])
    }
    
    for i,v := range arr{
        fmt.Println(i,v)
    }

}

数组的注意点

        go语言中数组长度数据类型的一部分,长度不同类型不同,不能比较。

        go语言数组类型相同,在比较时会按照“对应索引的元素”进行比较,所有元素都相同返回true,否则返回false

        go语言的数组是值类型,赋值和传参会复制整个数组

package main
import "fmt"
func main(){
    var arr1 [2]int
    var arr2 [3]int
    var arr3 [3]int
    var arr4 [3]int
    fmt.Println(arr2 == arr3) // true
// go语言中数组长度是数据类型的一部分,长度不同类型不同,不能比较。
    //fmt.Println(arr1 == arr2) 编译报错 

//go语言数组类型相同,在比较时会按照“对应索引的元素”进行比较,所有元素都相同返回true,否则返回false
    arr2 = [3]int{1,2,3}
    arr3 = [3]int{1,2,3}
    arr4 = [3]int{3,2,1}
    fmt.Println(arr2 == arr3) // true
    fmt.Println(arr2 == arr4) // false

//go语言的数组是值类型,赋值和传参会复制整个数组
    arr4 = arr2
    arr2[0]=3
    fmt.Println(arr2) //[3 2 3] 
    fmt.Println(arr4) //[1 2 3]
        
}

二维数组

package main
import "fmt"
func main(){
    //创建一个两行三列数组
    arr := [2][3]int{
        {1,2,3},
        {4,5,6},  //注意:数组换行需要逗号结尾
    }
    fmt.Println(arr) //[[1 2 3][4 5 6]]

    //创建多维数组只允许第一维使用 ... 
    arr1 := [...][3]int{
        {1,2,3},
        {4,5,6}
    }
    fmt.Println(arr1)
}

切片可以简单理解为长度可以变化的数组,但是go语言的切片本质上是结构体,用来解决数组在应用中长度不可变的问题

切片源码

type slice struct{

        array  unsafe.Pointer        //指向底层数组指针

        len int        //切片长度(已经保存了多少个元素)

        cap int     //切片容量(可以保存多少个元素)   

}

切片的创建方式

package main
import "fmt"
func main(){
//1.通过数组创建切片----------------------(切片的底层会指向数组,修改切片会修改对应位数组的值)
    var arr = [5]int{1,3,5,7,9}
    var sce = arr[1:3]        //从下标1开始,一直取到3下标的前一个索引(左闭右开)
    fmt.Println(sce)          //[3 5]  
    fmt.Println(len(sce))     //切片的长度2 = 3 - 1 结束位置减开始位置
    fmt.Println(cap(sce))     //切片的容量4 = 5 - 1 数组长度减开始位置
    
    fmt.Printf("%p\n",&arr)      
    fmt.Printf("%p\n",&arr[0]) //数组地址 是 数组首元素地址   
    fmt.Printf("%p\n",&arr[1]) 
    fmt.Printf("%p\n",sce)     //切片地址 是数组中指定的 开始元素的地址 (&arr[1])

   //指定骑士位置的四种方式
    var sce1 = arr[1:2]  //指定开始和结束
    var sce2 = arr[:2]   //只指定结束
    var sce3 = arr[2:]   //只指定开始
    var sce4 = arr[:]    //都不指定 

//2.通过make函数创建q切片     make(类型,长度,容量) 
   //内部会先创建一个数组,然后让切片指向数组
   //如果没有指定容量,那么容量和长度一样
    var sce5 = make([]int,3,5)
    fmt.Println(sce5)         //[0 0 0]
    fmt.Println(len(sce5))    //3
    fmt.Println(cap(sce5))    //5
   /*实现
    var arr [5]int        
    var sce = arr[0:3]
   */

//3.通过go提供的语法糖快速创建
   //和创建数组相同,但是不能指定长度
   //创建时,切片的容量和长度相等
    var sce6 = []int{1,3,5}
    fmt.Println(sce6)         
    fmt.Println(len(sce6))     //3
    fmt.Println(cap(sce6))     //3

    
}

切片的使用

package main
import "fmt"
func main(){
    var sce = []int{1,3,5}
//1.同数组一样,使用  切片名称[索引] 的方式操作切片
    sce[1] = 666

//2.不能越界
    sce[5] = 1 //编译报错

//3.使用append方法对切片扩容----------------------------(返回新切片不会修改源底层指向数组)
    //append(切片,元素)会在切片末尾添加一个元素,返回追加数据之后的切片
    //追加后没有查出切片容量,返回原切片,超出容量返回新切片
    //append 每次扩容会按照(原有切片容量*2)的方式扩容
    
    fmt.Println(sce)        //[1,666,5]   
    fmt.Println(len(sce))   //3
    fmt.Println(cap(sce))   //3
    fmt.Printf("%p\n",sce)  //一个地址 


    sce = append(sce , 666)
    fmt.Println(sce)        //[1,666,5,666]   
    fmt.Println(len(sce))   //4
    fmt.Println(cap(sce))   //6
    fmt.Printf("%p\n",sce)  //一个新地址 


//4.使用copy用于两个切片之间数据拷贝   copy(目标切片,切片源)
    var sce1 = []int{1,2,3}
    var sce2 = make([]int,5)
    var sce3 = make([]int,2)
   //复制sce1的切片数据到sce2,这时他们的内存指向地址不同
    copy(sce2,sce1)        //sce2 [1,2,3,0,0]
   //拷贝数据以小容量为准
    copy(sce3,sce1)        //sce3 [1,2]

//切片是引用传递 底层会指向同一个数组,再次修改sce2,sce1也会变
    sce2 = sce1 
}

切片的注意点

package main
import "fmt"
func main(){
//1.可以通过切片中再次生成新的切片,两个切片底层指向同一数组,修改一个会影响另一个
    arr := [5]int{1,3,5,7,9}
    sce1 := arr[0:4]
    sce2 := sce1[0:3]
    fmt.Println(sce1) //[1 3 5 7]
    fmt.Println(sce2) //[1 3 5]
    sce2[1] = 666
    fmt.Println(sce1) //[1 666 5 7] 
    fmt.Println(sce2) //[1 666 5]
    fmt.Println(arr) //[1,666,5,7,9] 会修改指向的数组

//2.切片只支持判断是否为nil,不支持==、!= 判断
    //fmt.Println(sce1 == sce2)//编译报错
    fmt.Println(sce1 != nil)//true
    fmt.Println(sce2 == nil)//false

//3.只声明当没有被创建的切片是不能使用的
    var arr [3]int //数组声明后直接可使用

    var sce []int  //切片生命后不能直接使用 只有通过make或者放糖创建后才会开辟空间使用
    var sce[0] = 2 //编译报错

//4.字符串的底层是[]byte数组,所以字符也支持切片操作
    str := "abcdefg"
    sce1 := str[3:]
    fmt.Println(sce1)

    sce2 := make([]byte,10)
    //第二个参数只能是slice或者数组
    //将字符串拷贝到切片中
    copy(sce2,str)
    fmt.Println(sce2) //[97 98 99 100 101 102 103 0 0 0]


}

下一篇转载  go切片与数组的关系—修改切片导致数组被修改的问题_shockWaveGo的博客-CSDN博客

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值