Description
- 判断下面代码能否通过编译
func main() {
s1 := []int{1, 2, 3}
s2 := []int{4, 5}
s1 = append(s1, s2)
fmt.Println(s1)
}
解析:append
的第二个参数不能直接使用slice
,需要使用...
操作符,将一个切片追加到另一个切片上,或者直接跟上元素append(s1, 1, 2, 3)
。
- 以下代码的输出是什么
func main() {
a := []int{7, 8, 9}
fmt.Printf("%+v\n", a)
ap(a)
fmt.Printf("%+v\n", a)
app(a)
fmt.Printf("%+v\n", a)
}
func ap(a []int) {
a = append(a, 10)
}
func app(a []int) {
a[0] = 1
}
输出:
[7, 8, 9]
[7, 8, 9]
[1, 8, 9]
解析:append
导致底层数组重新分配了内存,ap
中的a
的底层数组与外部的a
不是同一个,并未改变外部的。
- 切片的截取操作符
package main
import (
"fmt"
)
func main() {
a := [5]int{1, 2, 3, 4, 5}
t := a[3:4:4]
fmt.Println(t[0])
}
解析:假设一个底层数组a
的大小是n
,截取切片的操作是a[i: j]
,则获得的切片长度为j - i
,容量为n - i
。如果截取操作符存在第三个参数k
,其是用来限制新切片容量的。
- 下面代码下划线处可以填入哪个选项
func main() {
var s1 []int
var s2 = []int{}
if __ == nil {
fmt.Println("yes nil")
}else{
fmt.Println("no nil")
}
}
答案:s1
。
解析:nil
切片和 nil
相等,一般用来表示一个不存在的切片;空切片和 nil
不相等,表示一个空的集合。
- 两种切片声明
-
var a []int
声明nil
切片; -
a := []int{}
声明长度和容量都为0
的空切片。
- 切片
a
、b
、c
的长度和容量分别是多少?
func main() {
s := [3]int{1, 2, 3}
a := s[:0]
b := s[:2]
c := s[1:2:cap(s)]
}
答案:a
、b
、c
的长度和容量分别是 0 3
、2 3
、1 2
。
解析:假设一个底层数组a
的大小是n
,截取切片的操作是a[i: j]
,则获得的切片长度为j - i
,容量为n - i
。如果截取操作符存在第三个参数k
,其是用来限制新切片容量的。
- 下面这段代码输出什么
func main() {
s1 := []int{1, 2, 3}
s2 := s1[1:]
s2[1] = 4
fmt.Println(s1)
s2 = append(s2, 5, 6, 7)
fmt.Println(s1)
}
输出:
[1 2 4]
[1 2 4]
解析:
Go
中切片底层的数据结构是数组。当使用 s1[1:]
获得切片 s2
,和 s1
共享同一个底层数组,这会导致 s2[1] = 4
语句影响 s1
。
而 append
操作会导致底层数组扩容,生成新的数组,因此追加数据后的 s2
不会影响 s1
。
但是为什么对 s2
赋值后影响的却是 s1
的第三个元素呢?这是因为切片 s2
是从数组的第二个元素开始,s2
索引为 1
的元素对应的是 s1
索引为 2
的元素。
- 下面的代码有什么问题
func main() {
fmt.Println([...]int{1} == [2]int{1})
fmt.Println([]int{1} == []int{1})
}
解析:go
中不同类型是不能比较的,而数组长度是数组类型的一部分,所以 […]int{1} 和 [2]int{1}
是两种不同的类型,不能比较;切片是不能比较的。
- 下面这段代码输出什么
func change(s ...int) {
s = append(s,3)
}
func main() {
slice := make([]int,5,5)
slice[0] = 1
slice[1] = 2
change(slice...)
fmt.Println(slice)
change(slice[0:2]...)
fmt.Println(slice)
}
输出:
[1 2 0 0 0]
[1 2 3 0 0]
解析:
Go
提供的语法糖...
,可以将 slice
传进可变函数,不会创建新的切片。
第一次调用 change()
时,append()
操作使切片底层数组发生了扩容,原 slice
的底层数组不会改变;
第二次调用 change()
函数时,获得一个新的切片,它的底层数组和原切片底层数组是重合的,不过长度、容量分别是 2、5,所以在 change()
函数中对底层数组的修改会影响到原切片。
- 下面这段代码输出什么
var x = []int{2: 2, 3, 0: 1}
func main() {
fmt.Println(x)
}
输出:[1 0 2 3]
解析:字面量初始化切片时候,可以指定索引,没有指定索引的元素会在前一个索引基础之上加一,所以输出 [1 0 2 3]
,而不是 [1 3 2]
。
- 下面的这段代码输出是什么
func main() {
a := [2]int{5, 6}
b := [3]int{5, 6}
if a == b {
fmt.Println("equal")
} else {
fmt.Println("not equal")
}
}
编译出错,Go
中的数组是值类型,可以进行比较,同时数组长度也是数组类型的组成部分,并且Go
语言是强类型语言,所以上面的a, b
不能进行比较,编译出错。
- 下面的这段代码输出什么
package main
import "fmt"
func main() {
s := make([]int, 3, 9)
fmt.Println(len(s))
s2 := s[4:8]
fmt.Println(len(s2))
}
输出:3 4
解析:从一个基础切片派生出的子切片的长度可能大于基础切片的长度。
- 下面哪一行代码会
panic
package main
func main() {
var m map[int]bool // nil
_ = m[123]
var p *[5]string // nil
for range p {
_ = len(p)
}
var s []int // nil
_ = s[:]
s, s[0] = []int{1, 2}, 9
}
解析:s, s[0] = []int{1, 2}, 9
行。因为左侧的 s[0]
中的 s
为 nil
。
- 下面这段代码输出什么
func main() {
var k = 1
var s = []int{1, 2}
k, s[k] = 0, 3
fmt.Println(s[0] + s[1])
}
输出:4
解析:多重赋值按照以下的两个步骤进行:计算等号左边的索引表达式和取址表达式,接着计算等号右边的表达式;赋值。