切片

切片实际上是一个Go的数据结构,我们可以增加更多的值。与数组相同的是,切片由多个相同类型的元素构成。不同的是,切片允许我们在结尾追加更多的元素。

声明

使用一对空的方括号,后面跟着这个切片所保存的元素类型。

  • 除了不指定大小,与声明一个数组变量的语法完全相同。

    image-20201028092029558

    image-20201028092104428

    不像数组变量,声明切片变量并不会自动创建一个切片。为此,你可以调用内建的make函数。传递给make你想要创建的切片的类型(这个类型与你想要赋值的变量的类型相同)和需要创建的切片的长度。

    package main
    
    import "fmt"
    
    func main() {
     	var sta []string
     	sta=make([]string,7)
     	fmt.Printf("%#v",sta)
    }

    image-20201028092458579


切片中元素的赋值和取值操作

当切片被创建后,切片中元素的赋值和取值操作语法与数组的相同。

package main

import "fmt"

func main() {
 	var sta []string
 	sta=make([]string,7)
 	sta[2]="sss"
 	fmt.Printf("%#v",sta)
}

image-20201028092820867


推导出变量的类型

不必将声明变量和创建切片分成两步,使用一个短变量声明的make会自动帮你推导出变量的类型。

package main
import "fmt"
func main() {
 	sta:=make([]string,8)
 	sta[2]="sss"
 	fmt.Printf("%#v",sta)
}

image-20201028093118407


切片操作

内建的函数len对于切片也和数组有相同的效果。将一个切片的变量传入len,会返回一个整型的长度值。

package main
import "fmt"
func main() {
 	sta:=make([]string,8)
 	sta[2]="sss"
 	fmt.Print(len(sta))
 	fmt.Printf("%#v",sta)
}

image-20201028093301643

for和for…range对于切片的操作也和数组相同:

package main
func main() {
 	sta:=make([]string,8)
 	sta[2]="sss"
	for i,v := range sta {
		print(i,":"+v," ")
	}
	println()
	for i:=0;i<len(sta);i++{
		print(i,":"+sta[i]," ")
	}
}

image-20201028093637807


切片字面量

与数组相同,如果最初知道切片初始会有哪些值,可以使用切片字面量来通过这些值初始化切片。切片字面量看起来和数组字面量非常像,但是数组字面量在方括号中有数组的长度,而切片字面量的方括号中是空的。空的括号后面是切片储存的元素的类型,还有一个在花括号中的列表,列表中是每个元素的初始值。这里不需要调用make函数;

在代码中使用一个切片字面量会创造一个预填充的切片。

image-20201028093957913

  • 因为切片是建立在数组之上的。

切片运算符

每一个切片都构建于一个底层的数组之上。实际上是底层的数组存储了切片的数据;切片仅仅是数组中的一部分(或者所有)元素的视图。

当你使用make函数或者切片字面量创建一个切片的时候,底层的数组会自动创建出来(只有通过切片,你才能访问它)。但是你也可以自己创建一个数组,然后再基于数组通过切片运算符创建一个切片。

切片运算符看起来像访问一个切片或者数组的某个元素的语法,但是它有两个索引:其中一个标识切片开始的位置,另一个标识切片在此位置之前结束。

package main
import "fmt"
func main() {
 	sta:=make([]string,8)
 	sta[2]="sss"
 	stb:=sta[1:3]
	fmt.Printf("%#v\n",sta)
	fmt.Printf("%#v",stb)
}

image-20201028094338167

  • 注意我们强调切片需要在第二个位置之前结束。切片应该包含从开始到第二个索引之前的元素。如果你使用underlyingArray[i:j]作为切片的运算符,生成的切片实际上包含元素underlyingArray[i]到元素underlyingArray[j-1]。

切片运算符默认需要两个索引。如果你忽略了开始的索引,0(数组的第一个元素)会被使用。

package main

import "fmt"

func main() {
 	sta:=make([]string,8)
 	sta[2]="sss"
 	stb:=sta[:3]
	fmt.Printf("%#v\n",sta)
	fmt.Printf("%#v",stb)
}

image-20201028095946816

如果你忽略了结束的索引,从底层数组的开始索引到数组结尾之间的所有元素都会被包含到结果切片中。

package main

import "fmt"

func main() {
 	sta:=make([]string,8)
 	sta[2]="sss"
 	stb:=sta[2:]
	fmt.Printf("%#v\n",sta)
	fmt.Printf("%#v",stb)
}

image-20201028100049006

底层数组

片并不会自己保存任何数据,它仅仅是底层数组的元素的视图。你可以把切片看作一个显微镜,聚焦在胶片(底层数组)内容的特定部分。

使用切片的时候,仅仅可以操作通过切片可见的部分。

image-20201028100710272

每一个切片会是一个指向数组元素的子集的视图。切片甚至可以有重叠!


修改底层数组,修改切片

由于切片只是底层数组内容的视图,如果你修改底层数组,这些变化也会反映到切片。

给切片的一个元素赋一个新值也会修改底层数组相应的元素。

如果多个切片指向了同一个底层数组,数组的元素修改会反映给所有的切片。

package main

import "fmt"

func main() {
	var sta []int=[]int{1,2,3,4,5,6,7,8,9}
	stb:=sta[:5]
	stc:=sta[3:]
	sta[4]=14
	stb[2]=22
	stc[2]=12
	fmt.Printf("%#v\n",sta)
	fmt.Printf("%#v\n",stc)
	fmt.Printf("%#v",stb)
}

image-20201028101522929

由于这些问题,你应该已经发现通常我们使用make和切片字面量来创建切片,而不是创建一个数组,再用一个切片在上面操作。

使用了make和切片字面量,你就不用关心底层数组了。


“append”函数

Go提供一个内建的函数append来将一个或者多个值追加到切片的末尾。它返回一个与原切片元素完全相同的并且在尾部追加了新元素的新的更大的切片。

你不需要记住你需要追加到尾部的新值的索引!仅仅调用append函数并且传入切片和你需要追加到末尾的值,你就会得到一个新的更长的切片。非常简单!

package main
import "fmt"
func main() {
	var sta []int=[]int{1,2,3}
	//sta:=[]int{1,2,3}
	stb := append(sta, 4, 5, 6, 7, 8, 9)
	stc := stb[:]
	sta[2]=12
	stb[6]=16
	fmt.Printf("%#v\n",sta)
	fmt.Printf("%#v\n",stb)
	fmt.Printf("%#v\n",stc)
}

image-20201028103158285

变长参数函数

为了让函数的参数可变长,在函数声明中的最后的(或者仅有的)参数类型前使用省略号(…)。

Go为这种情况提供了一个特殊的语法。当我们调用一个可变长参数函数时,简单地在你传入的切片变量后增加省略号(…)即可。

package main

import "math"

func max(age ...float64) float64 {
	m:=math.Inf(-1)
	for _,v := range age {
		if m<v {
			m=v
		}
	}
	return m
}
func main() {
	m:=[]float64{1,2,3}
	print(max(m...))
}

image-20201028110114403


本博客所有文章除特别声明外,均采用 CC BY-SA 4.0 协议 ,转载请注明出处!

映射 上一篇
下一篇