Golang数组与切片

05-13 1719阅读

文章目录

  • 数组
    • 数组介绍
    • 数组的定义方式
    • 访问与修改数组元素
    • 遍历数组元素
    • 数组指针
    • 切片
      • 切片介绍
      • 切片的定义方式
      • 访问与修改切片元素
      • 添加切片元素
      • 切片的拷贝
      • 遍历切片元素
      • string的切片

        数组

        数组介绍

        数组介绍

        • 在Go中,数组是一个由固定长度的特定类型元素组成的序列,一个数组可以由零个或多个元素组成。
        • 长度是数组类型的一部分,数组声明后长度不能动态变化,只有数组元素类型相同并且数组长度相同,才算同一种数组类型。
        • 数组创建后,如果没有对数组元素进行赋值,则保留对应元素类型的默认值(数值类型为0,string类型为"",bool类型为false,引用类型为nil)。

          数组的示意图如下:

          Golang数组与切片

          数组的定义方式

          数组的定义方式

          方式一: 指明数组长度和元素类型,数组元素采用对应的默认值。

          var arr1 [5]int
          fmt.Printf("arr1 = %v\n", arr1)      // arr1 = [0 0 0 0 0]
          fmt.Printf("arr1 type = %T\n", arr1) // arr1 type = [5]int
          

          方式二: 指明数组长度和元素类型,并初始化数组元素。

          var arr2 = [5]int{1, 2, 3, 4, 5}
          fmt.Printf("arr2 = %v\n", arr2)      // arr2 = [1 2 3 4 5]
          fmt.Printf("arr2 type = %T\n", arr2) // arr2 type = [5]int
          

          方式三: 指明数组长度并初始化数组元素,数组长度根据初始化值的个数计算。

          var arr3 = [...]int{1, 2, 3, 4, 5}
          fmt.Printf("arr3 = %v\n", arr3)      // arr3 = [1 2 3 4 5]
          fmt.Printf("arr3 type = %T\n", arr3) // arr3 type = [5]int
          

          方式四: 通过索引的方式,对数组中对应的元素进行初始化。

          var arr4 = [...]int{1: 20, 4: 100, 0: -1, 2: 9}
          fmt.Printf("arr4 = %v\n", arr4)      // arr4 = [-1 20 9 0 100]
          fmt.Printf("arr4 type = %T\n", arr4) // arr4 type = [5]int
          

          访问与修改数组元素

          访问与修改数组元素

          Go中通过数组名[下标]的方式对数组元素进行访问和修改。如下:

          package main
          import "fmt"
          func main() {
          	// 访问与修改数组元素
          	var arr = [...]int{1, 2, 3, 4, 5}
          	fmt.Printf("arr[3] = %d\n", arr[3]) // arr[3] = 4
          	arr[3] += 10
          	fmt.Printf("arr = %v\n", arr) // arr = [1 2 3 14 5]
          }
          

          说明一下:

          • 数组中元素的下标从0开始,访问数组元素时下标必须在指定范围内,否则会产生报错。

            遍历数组元素

            for循环遍历

            通过for循环对数组元素的下标进行迭代,然后通过数组名[下标]的方式访问数组中的各个元素。如下:

            package main
            import "fmt"
            func main() {
            	// 遍历数组元素
            	var arr = [...]int{1, 2, 3, 4, 5}
            	for i := 0; i  
            

            说明一下:

            • len是Go中的内建函数,可以用于获取数组的长度。

              for range遍历

              通过for range循环也能完成对数组元素的遍历。如下:

              package main
              import "fmt"
              func main() {
              	// 遍历数组元素
              	var arr = [...]int{1, 2, 3, 4, 5}
              	for index, value := range arr {
              		fmt.Printf("arr[%d] = %d\n", index, value)
              	}
              }
              

              说明一下:

              • 在for range循环中遍历数组时,每次迭代会返回两个值,第一个是元素的索引,第二个是元素的值,当遍历结束后会自动退出for range循环。

                数组指针

                数组指针

                数组属于值类型,采用值传递的方式进行传参,函数内部对数组的操作不会影响到原始数组,如果希望在函数中对数组的操作影响到原始数组,可以通过数组指针的方式进行传参。如下:

                package main
                import "fmt"
                func ModifyArray(arr *[5]int) {
                	for i := 0; i  
                

                说明一下:

                • 数组的地址通过&数组名的方式来获取,其与数组中第一个元素的地址相同。
                • len函数可以接收数组指针作为参数,Go会自动对指针进行解引用,并返回该数组的长度。
                • 在Go中,可以通过数组指针[下标]的方式访问数组元素,Go会自动对指针进行解引用并将其视为一个数组。

                  切片

                  切片介绍

                  切片介绍

                  • 在Go中,切片(Slice)代表变长的序列或动态数组,序列中每个元素都有相同的类型。
                  • 切片是数组的引用,主要由三部分构成:指针、长度和容量,指针指向底层引用的数组,长度代表切片中实际存储的元素个数,容量代表数组中可容纳的元素个数。

                    切片的示意图如下:

                    Golang数组与切片

                    切片属于引用类型,当切片类型变量进行赋值或传参时,本质就是将切片中的指针、长度和容量三个字段的值进行拷贝,因此最终两个切片变量底层指向的是同一个数组,其中一个变量对数组修改会影响到另一个切片变量。如下:

                    Golang数组与切片

                    切片的定义方式

                    方式一:引用现有数组

                    在定义切片时,可以通过数组名[起始下标:结束下标]的方式引用现有数组。如下:

                    package main
                    import "fmt"
                    func main() {
                    	// 方式一:引用现有数组
                    	var arr = [10]int{1, 2, 3, 4, 5, 6, 7, 8, 9, 10}
                    	var slice = arr[3:6]
                    	fmt.Printf("slice = %v\n", slice)    // slice = [4 5 6]
                    	fmt.Printf("len = %d\n", len(slice)) // len = 3
                    	fmt.Printf("cap = %d\n", cap(slice)) // cap = 7
                    }
                    

                    在上述代码中,切片与数组的关系示意图如下:

                    Golang数组与切片

                    说明一下:

                    • 切片定义后需要先让其引用到一个数组,数组名[起始下标:结束下标]表示引用数组[起始下标, 结束下标)范围内的元素,如果从数组的第一个元素开始引用,则起始下标可省略,如果引用到数组的最后一个元素,则结束下标可省略。
                    • 通过引用现有数组创建的切片,切片的指针字段指向引用数组中起始下标位置的元素,长度字段为起始下标到结束下标的长度,容量字段通常为起始下标到数组末尾的长度。
                    • len和cap都是Go中的内建函数,len函数可以用于获取切片的长度,cap函数可以用于获取切片的容量。
                    • 通过引用现有数组创建的切片,切片底层指向的就是被引用的数组,因此通过切片对数组进行的修改会影响到被引用的数组。
                    • 创建切片时也可以引用现有的切片,其引用方式和底层原理与引用现有的数组类似。

                      方式二:make切片

                      在定义切片时,可以通过make创建指定长度和容量的切片。如下:

                      package main
                      import "fmt"
                      func main() {
                      	// 方式二:make切片
                      	var slice = make([]int, 5, 10)
                      	fmt.Printf("slice = %v\n", slice)    // slice = [0 0 0 0 0]
                      	fmt.Printf("len = %d\n", len(slice)) // len = 5
                      	fmt.Printf("cap = %d\n", cap(slice)) // cap = 10
                      }
                      

                      在上述代码中,切片示意图如下:

                      Golang数组与切片

                      说明一下:

                      • make是Go中的内建函数,可以用于分配并初始化一个指定长度和容量的切片,其第一个参数表示切片的类型,第二个参数表示切片的长度,第三个参数表示切片的容量,第三个参数若省略则默认等于切片的长度。
                      • 使用make函数创建切片时,Go运行时会在堆上分配一块连续的内存区域来存储切片的底层数组,该数组的长度和容量根据传递给make函数的参数确定。
                      • 通过make的方式创建切片后,如果没有给切片中的元素赋值,则保留对应元素类型的默认值(数值类型为0,string类型为"", bool类型为false,引用类型为nil)。

                        方式三:指定具体数组

                        在定义切片时,也可以直接指定具体的数组。如下:

                        package main
                        import "fmt"
                        func main() {
                        	// 方式三:指定具体数组
                        	var slice = []int{1, 2, 3, 4, 5}
                        	fmt.Printf("slice = %v\n", slice)    // slice = [1 2 3 4 5]
                        	fmt.Printf("len = %d\n", len(slice)) // len = 5
                        	fmt.Printf("cap = %d\n", cap(slice)) // cap = 5
                        }
                        

                        在上述代码中,切片示意图如下:

                        Golang数组与切片

                        说明一下:

                        • 通过指定具体数组创建切片时,Go运行时也会在堆上分配一块连续的内存区域来存储切片的底层数组,该数组的长度和容量与指定的数组的长度相同,并根据指定的数组来初始化底层数组的元素值。

                          访问与修改切片元素

                          访问与修改切片元素

                          Go中通过切片名[下标]的方式对切片元素进行访问和修改。如下:

                          package main
                          import "fmt"
                          func main() {
                          	// 访问与修改切片元素
                          	var arr = [10]int{1, 2, 3, 4, 5, 6, 7, 8, 9, 10}
                          	var slice = arr[3:6]
                          	fmt.Printf("slice[2] = %d\n", slice[2]) // slice[2] = 6
                          	slice[2] += 10
                          	fmt.Printf("slice = %v\n", slice) // slice = [4 5 16]
                          	fmt.Printf("arr = %v\n", arr)     // arr = [1 2 3 4 5 16 7 8 9 10]
                          }
                          

                          说明一下:

                          • 切片中元素的下标从0开始,访问切片元素时下标必须在指定范围内,否则会产生报错。
                          • 上述代码中通过引用现有数组创建了切片,因此对切片元素修改后被引用数组中对应的元素也被修改。

                            添加切片元素

                            添加切片元素

                            Go中通过append函数在切片末尾追加元素。如下:

                            package main
                            import "fmt"
                            func main() {
                            	// 添加切片元素
                            	var slice = []int{1, 2, 3, 4, 5}
                            	var slice2 = append(slice, 6, 7, 8)
                            	fmt.Printf("slice = %v\n", slice)   // slice = [1 2 3 4 5]
                            	fmt.Printf("slice2 = %v\n", slice2) // slice2 = [1 2 3 4 5 6 7 8]
                            	slice = append(slice, slice2...)
                            	fmt.Printf("slice = %v\n", slice) // slice = [1 2 3 4 5 1 2 3 4 5 6 7 8]
                            }
                            

                            说明一下:

                            • append是Go中的内建函数,用于在切片的末尾追加一个或多个元素,其第一个参数表示被追加的切片,第二个参数是可变参数类型,可以接收多个待追加的元素。
                            • append函数在追加元素时,如果被追加的切片容量足够,则直接在切片后追加元素,否则会重新分配一个更大的空间来存储追加后的结果,并将追加后的切片返回。
                            • 对于切片类型的变量来说,可以通过切片名...的方式将切片中的元素展开成独立的元素序列。

                              切片的拷贝

                              切片的拷贝

                              Go中通过copy函数完成切片的拷贝操作。如下:

                              package main
                              import "fmt"
                              func main() {
                              	// 切片的拷贝
                              	var slice = []int{1, 2, 3, 4, 5}
                              	var slice2 = make([]int, 5)
                              	fmt.Printf("slice = %v\n", slice)   // slice = [1 2 3 4 5]
                              	fmt.Printf("slice2 = %v\n", slice2) // slice2 = [0 0 0 0 0]
                              	copy(slice2, slice)
                              	fmt.Printf("slice = %v\n", slice)   // slice = [1 2 3 4 5]
                              	fmt.Printf("slice2 = %v\n", slice2) // slice2 = [1 2 3 4 5]
                              	for i := 0; i  
                              

                              在上述代码中,两个切片的示意图如下:

                              Golang数组与切片

                              说明一下:

                              • copy是Go中的内建函数,用于将一个切片中的元素拷贝到另一个切片中,其第一个参数代表目标切片,第二个参数代表源切片。
                              • copy函数在拷贝切片时,会将底层的数组也进行一份拷贝,因此拷贝后两个切片底层引用的是不同的数组,彼此之间不会相互影响。
                              • copy函数在拷贝时,如果源切片与目标切片的长度不同,则会选择两者之间较小的值作为拷贝元素的数量。

                                遍历切片元素

                                for循环遍历

                                通过for循环对切片元素的下标进行迭代,然后通过切片名[下标]的方式访问切片中的各个元素。如下:

                                package main
                                import "fmt"
                                func main() {
                                	// 遍历切片元素
                                	var slice = []int{1, 2, 3, 4, 5}
                                	for i := 0; i  
                                 
                                 

                                for range遍历

                                通过for range循环也能完成对切片元素的遍历。如下:

                                package main
                                import "fmt"
                                func main() {
                                	// 遍历切片元素
                                	var slice = []int{1, 2, 3, 4, 5}
                                	for index, value := range slice {
                                		fmt.Printf("slice[%d] = %d\n", index, value)
                                	}
                                }
                                

                                说明一下:

                                • 在for range循环中遍历切片时,每次迭代会返回两个值,第一个是元素的索引,第二个是元素的值,当遍历结束后会自动退出for range循环。

                                  string的切片

                                  string的切片

                                  Go中的string是由单个字节连接起来的,其底层就是一个byte数组,因此string也可以进行切片处理。如下:

                                  package main
                                  import "fmt"
                                  func main() {
                                  	// string的切片
                                  	var s string = "Hello World"
                                  	var s2 = s[1:]
                                  	fmt.Printf("s = %s\n", s)        // s = Hello World
                                  	fmt.Printf("s2 = %s\n", s2)      // s2 = ello World
                                  	fmt.Printf("s2 type = %T\n", s2) // s2 type = string
                                  }
                                  

                                  在上述代码中,两个string的示意图如下:

                                  Golang数组与切片

                                  说明一下:

                                  • 由于string在Go中是不可变的,因此对string进行切片操作只是生成了一个新的string,表示原始string的子串,这个子串仍然是string类型,它们底层引用的是同一个字符串。

                                    由于string的切片仍然是string类型,因此是不可变的,如果希望对字符串进行修改,需要先将其转换为[]byte或[]rune类型。如下:

                                    package main
                                    import "fmt"
                                    func main() {
                                    	// string的切片
                                    	var s string = "Hello World"
                                    	var slice = []byte(s)
                                    	slice[2] = 'x'
                                    	fmt.Printf("s = %s\n", s)              // s = Hello World
                                    	fmt.Printf("slice = %s\n", slice)      // slice = Hexlo World
                                    	fmt.Printf("slice type = %T\n", slice) // slice type = []uint8
                                    }
                                    

                                    说明一下:

                                    • 由于string是不可变的,为了保持其不可变性,在将string转换为[]byte或[]rune类型时,底层会创建一个新的byte切片或rune切片,其中包含字符串的副本,因此转换后的变量与原string底层引用的不是同一个字符串,彼此之间不会相互影响。
VPS购买请点击我

文章版权声明:除非注明,否则均为主机测评原创文章,转载或复制请以超链接形式并注明出处。

目录[+]