任务描述
请用户实现一个名为slice_add
的函数,要求该函数能合并两个slice
的全部元素到一个新的slice
,并返回新slice
的长度len
和容量cap
。
相关知识
Go 语言数组我们在之前的实训中已经学习过,那个实训曾经提过一句话:切片slice
类型构建于数组之上,所以掌握数组是后面学习slice
的基础。本关我们继续讲一下数组,让学员更好地理解数组和slice
的区别。
数组和slice的区别
Go 语言中数组是具有固定长度而且拥有零个或者多个相同或相同数据类型元素的序列。由于数组长度固定,所以在 Go 语言比较少直接使用。而slice
长度可增可减,使用场合比较多。更深入的区别在于:数组在使用的过程中都是值传递,将一个数组赋值给一个新变量或作为方法参数传递时,是将源数组在内存中完全复制了一份,而不是引用源数组在内存中的地址。为了满足内存空间的复用和数组元素的值的一致性的应用需求,slice
出现了,每个slice
都是都源数组在内存中的地址的一个引用,源数组可以衍生出多个slice,slice
也可以继续衍生其他slice
。
数组
Go 语言数组中每个元素是按照索引来访问的,索引从 0 到数组长度减 1 。Go 语言内置函数len
可以返回数组中的元素个数。
数组定义初始化
初始化方式有四种:指定/不指定长度*初始化部分/全部元素两两组合。示例代码如下:
var a [3] int //3个整数型的数组,初始值是3个0
arr:=[5]int{1,2,3,4,5} //长度为5
var array2 = [...]int{6, 7, 8} //不声明长度
q := [...] int {1,2,3} //不声明长度
r := [...] int {99:-1} //长度为100的数组,只有最后一个是-1,其他都是0
数组作为函数参数
Go语言中数组也可以作为参数:
package main
import "fmt"
func modify_arr(array [5]int) {
array[0]=10
fmt.Println("In modify_arr,array values is:",array)
}
func main() {
arr:=[5]int{1,2,3,4,5}
modify_arr(arr)
fmt.Println("In main,array values is:",arr)
}
slice
Go 语言中数组是值类型,长度不可伸缩;而slice
是引用类型,长度可动态增长。
slice概念
Go 语言中,slice
表示一个拥有相同类型元素的可变长度序列。slice
通常被写为[]T
,其中元素的类型都是T
;它看上去就像没有长度的数组类型。
数组和slice
其实是紧密关联的。slice
可以看成是一种轻量级的数据结构,可以用来访问数组的部分或者全部元素,而这个数组称之为slice
的底层数组。slice
有三个属性:指针,长度和容量。指针指向数组的第一个可以从slice
中访问的元素,这个元素不一定是数组的第一个元素。长度指的是slice
中的元素个数,不能超过slice
的容量。指针通常是从指向数组的第一个可以从slice
中访问的元素,这个元素不一定是数组的第一个元素。长度指的是slice
中的元素个数,它不能超过slice
的容量。容量的大小通常大于等于长度,会随着元素个数增多而动态变化。Go 语言的内置函数len
和cap
用来返回slice
的长度和容量。
slice定义初始化
slice
初始化依赖于数组,可见如下代码和注释:
s1 := []int{1, 2, 3} //注意与数组初始化的区别,在内存中构建一个包括有3个元素的数组,然后将这个数组的应用赋值给s这个slice
a := [10]int{1, 2, 3, 4, 5, 6, 7, 8, 9, 0} //a是数组
s2 := a[2:8] //从数组中切片构建slice
s3 := make([]int, 10, 20) //make函数初化,len=10,cap=20
其中a
是数组 ,s1,s2,s3
是slice
。
slice中len和cap关系
Go 语言的内置函数len
和cap
用来返回slice
的长度和容量。在追加元素时,如果容量cap
不足时,cap
一般变为原来的 2 倍来实现扩容。
slice
的cap
扩容规则:
- 如果新的
cap
大小是当前cap
的 2 倍以上,则直接扩容为这个新的cap
; - 否则循环以下操作:如果当前
cap
小于1024
,按每次 2 倍增长,否则每次按当前大小 1/4 增长。直到增长的大小超过或等于新的cap
。
slice
一般用append
函数追加元素,append
第一个参数是slice
,第二个参数是元素。示例代码如下:
package main
import "fmt"
func print_info(my_slice[]int) {
fmt.Println("len :",len(my_slice))
fmt.Println("cap :",cap(my_slice))
for i,v :=range my_slice{
fmt.Println("element[",i,"]=",v)
}
}
func main() {
my_slice01:=[]int{1,2,3,4,5}
my_slice02:=make([]int,5)
my_slice03:=make([]int,5,6)
my_slice04:=append(my_slice03,8,9,10)
print_info(my_slice01)
print_info(my_slice02)
print_info(my_slice03)
print_info(my_slice04)
}
slice作为函数参数
注意和数组作为函数参数的区别:
package main
import (
"fmt"
)
func main() {
a := []int{1, 2, 3, 4, 5}
var b = a[0:3]
var c = [...]int{3, 6, 9, 2, 6, 4}
d := c[0:2]
sliceInfo(b)
fmt.Printf("sum of b is %d\n", sum(b))
fmt.Printf("sum of d is %d\n", sum(d))
}
func sum(a []int) int {
s := 0
for i := 0; i < len(a); i++ {
s += a[i]
}
return s
}
func sliceInfo(x []int) {
fmt.Printf("len is %d ,cap is %d, slice is %v\n", len(x), cap(x), x)
}
slice的不可比性
Go 语言中slice
和 map ,func
一样,不支持 ==
操作符,就是不能直接比较,唯一合法的就是和nil
作比较。开发中经常会遇到需要比较两个slice
包含的元素是否完全相等的情况,这个时候只能遍历两个 slice
中的所有元素 ,看它们是否完全相等。
编程要求
本关的编程任务是在slice_func.go
文件中实现一个名为slice_add
的函数,补全Begin-End
之间的代码,要求该函数能合并两个slice
,并返回新slice
的长度len
和容量cap
。
本关涉及的代码文件sub_multi.go
的代码如下:
package main
import (
"fmt"
)
//请在此自定义一个名为slice_add的函数,
//要求该函数能合并两个slice,并返回新slice的长度len和容量cap。
//提示:结合之前学的函数不定参数
/********* Begin *********/
/********* End *********/
func main() {
s1 := []int{1, 2, 3, 4}
s2 := []int{1, 2, 3, 4, 5}
c,d := slice_add(s1,s2)
fmt.Println(c)
fmt.Println(d)
}
评测说明
本关卡的测试文件是slice_func.go
,具体测试过程如下:
1.平台自动编译生成slice_func.exe
; 2.平台运行slice_func.exe
; 3.获取slice_funci.exe
输出,并将其输出与预期输出对比:如果一致则测试通过,否则测试失败。
预期输入:
预期输出:
9
10
提示:append
的第一个参数是slice
,第二个参数是元素。结合下我们之前学的函数不定参数,学员可以思考下如何用append()
函数实现两个slice
的合并。
答案:
package main
import (
"fmt"
)
//请在此自定义一个名为slice_add的函数,
//要求该函数能合并两个slice,并返回新slice的长度len和容量cap。
//提示:结合之前学的函数不定参数
/********* Begin *********/
func slice_add(s1,s2 []int)(int,int){
newslice:=append(s1,s2...)
return len(newslice),cap(newslice)
}
/********* End *********/
func main() {
s1 := []int{1, 2, 3, 4}
s2 := []int{1, 2, 3, 4, 5}
c,d := slice_add(s1,s2)
fmt.Println(c)
fmt.Println(d)
}