本文转自公众号<Golang来啦> 仅作为一篇汇总
Day1
下面代码输出内容
package main
import "fmt"
func main() {
defer_call()
}
func defer_call() {
defer func() { fmt.Println("打印前") }()
defer func() { fmt.Println("打印中") }()
defer func() { fmt.Println("打印后") }()
panic("触发异常")
}
输出
打印后
打印中
打印前
panic: 触发异常
Day2
下面这段代码输出什么,说明原因。
func main() {
slice := []int{0,1,2,3}
m := make(map[int]*int)
for key,val := range slice {
m[key] = &val
}
for k,v := range m {
fmt.Println(k,"->",*v)
}
}
输出
0 -> 3
1 -> 3
2 -> 3
3 -> 3
解析:这是新手常会犯的错误写法,for range 循环的时候会创建每个元素的副本,而不是元素的引用,所以 m[key] = &val 取的都是变量 val 的地址,所以最后 map 中的所有元素的值都是变量 val 的地址,因为最后 val 被赋值为3,所有输出都是3.
Day3
1.下面两段代码输出什么。
// 1.
func main() {
s := make([]int, 5)
s = append(s, 1, 2, 3)
fmt.Println(s)
}
// 2.
func main() {
s := make([]int,0)
s = append(s,1,2,3,4)
fmt.Println(s)
}
2.下面这段代码有什么缺陷
func funcMui(x,y int)(sum int,error){
return x+y,nil
}
3.new() 与 make() 的区别
1.两段代码分别输出:
[0 0 0 0 0 1 2 3]
[1 2 3 4]
参考解析:这道题考的是使用 append 向 slice 添加元素,第一段代码常见的错误是 [1 2 3],需要注意。
参考答案:第二个返回值没有命名。 参考解析: 在函数有多个返回值时,只要有一个返回值有命名,其他的也必须命名。如果有多个返回值必须加上括号();如果只有一个返回值且命名也必须加上括号()。这里的第一个返回值有命名 sum,第二个没有命名,所以错误。
参考答案: new(T) 和 make(T,args) 是 Go 语言内建函数,用来分配内存,但适用的类型不同。
new(T) 会为 T 类型的新值分配已置零的内存空间,并返回地址(指针),即类型为 *T 的值。换句话说就是,返回一个指针,该指针指向新分配的、类型为 T 的零值。适用于值类型,如数组、结构体等。
make(T,args) 返回初始化之后的 T 类型的值,这个值并不是 T 类型的零值,也不是指针 *T,是经过初始化之后的 T 的引用。make() 只适用于 slice、map 和 channel.
Day4
1.下面这段代码能否通过编译,不能的话原因是什么;如果能,输出什么。
func main() {
list := new([]int)
list = append(list, 1)
fmt.Println(list)
}
2.下面这段代码能否通过编译,如果可以,输出什么?
func main() {
s1 := []int{1, 2, 3}
s2 := []int{4, 5}
s1 = append(s1, s2)
fmt.Println(s1)
}
3.下面这段代码能否通过编译,如果可以,输出什么?
var(
size := 1024
max_size = size*2
)
func main() {
fmt.Println(size,max_size)
}
参考解析
不能通过编译,new([]int) 之后的 list 是一个 *[]int 类型的指针,不能对指针执行 append 操作。可以使用 make() 初始化之后再用。同样的,map 和 channel 建议使用 make() 或字面量的方式初始化,不要用 new() 。
不能通过编译。append() 的第二个参数不能直接使用 slice,需使用 … 操作符,将一个切片追加到另一个切片上:append(s1,s2…)。或者直接跟上元素,形如:append(s1,1,2,3)。
参考答案及解析:不能通过编译。这道题的主要知识点是变量声明的简短模式,形如:x := 100。但这种声明方式有限制:
1.必须使用显示初始化;
2.不能提供数据类型,编译器会自动推导;
3.只能在函数内部使用简短模式;
Day5
下面这段代码能否通过编译?不能的话,原因是什么?如果通过,输出什么?
func main() {
sn1 := struct {
age int
name string
}{age: 11, name: "qq"}
sn2 := struct {
age int
name string
}{age: 11, name: "qq"}
if sn1 == sn2 {
fmt.Println("sn1 == sn2")
}
sm1 := struct {
age int
m map[string]string
}{age: 11, m: map[string]string{"a": "1"}}
sm2 := struct {
age int
m map[string]string
}{age: 11, m: map[string]string{"a": "1"}}
if sm1 == sm2 {
fmt.Println("sm1 == sm2")
}
}
参考解析
编译不通过 invalid operation: sm1 == sm2
这道题目考的是结构体的比较,有几个需要注意的地方:
- 结构体只能比较是否相等,但是不能比较大小。
- 相同类型的结构体才能够进行比较,结构体是否相同不但与属性类型有关,还与属性顺序相关,sn3 与 sn1 就是不同的结构体;
sn3:= struct { name string age int }{age:11,name:"qq"} - 如果 struct 的所有成员都可以比较,则该 struct 就可以通过 == 或 != 进行比较是否相等,比较时逐个项进行比较,如果每一项都相等,则两个结构体才相等,否则不相等;
注:bool、数值型、字符、指针、数组等可以比较,切片、map、函数等是不能比较的。
Day6
-
通过指针变量 p 访问其成员变量 name,有哪几种方式?
A.p.name B.(&p).name C.(*p).name D.p->name -
下面这段代码能否通过编译?如果通过,输出什么?
package main
import "fmt"
type MyInt1 int
type MyInt2 = int
func main() {
var i int =0
var i1 MyInt1 = i
var i2 MyInt2 = i
fmt.Println(i1,i2)
}
参考解析
-
AC。& 取址运算符,* 指针解引用。
-
编译不通过,cannot use i (type int) as type MyInt1 in assignment。
这道题考的是类型别名与类型定义的区别。
第 5 行代码是基于类型 int 创建了新类型 MyInt1,第 6 行代码是创建了 int 的类型别名 MyInt2,注意类型别名的定义时 = 。所以,第 10 行代码相当于是将 int 类型的变量赋值给 MyInt1 类型的变量,Go 是强类型语言,编译当然不通过;而 MyInt2 只是 int 的别名,本质上还是 int,可以赋值。第 10 行代码的赋值可以使用强制类型转化 var i1 MyInt1 = MyInt1(i).
Day7
-
关于字符串连接,下面语法正确的是?
A. str := 'abc' + '123' B. str := "abc" + "123" C. str := '123' + "abc" D. fmt.Sprintf("abc%d", 123) -
下面这段代码能否编译通过?如果可以,输出什么?
const (
x = iota
_
y
z = "zz"
k
p = iota
)
func main() {
fmt.Println(x,y,z,k,p)
}
-
下面赋值正确的是()
A. var x = nil B. var x interface{} = nil C. var x string = nil D. var x error = nil
参考解析
- 知识点:字符串连接。除了以上两种连接方式,还有 strings.Join()、buffer.WriteString()等。
- 编译通过,输出:0 2 zz zz 5。知识点:iota 的使用。给大家贴篇文章,讲的很详细 www.cnblogs.com/zsy/p/53700…
- BD。知识点:nil 值。nil 只能赋值给指针、chan、func、interface、map 或 slice 类型的变量。强调下 D 选项的 error 类型,它是一种内置接口类型,看下方贴出的源码就知道,所以 D 是对的。
type error interface { Error() string }
Day8
-
关于init函数,下面说法正确的是()
A. 一个包中,可以包含多个 init 函数; B. 程序编译时,先执行依赖包的 init 函数,再执行 main 包内的 init 函数; C. main 包中,不能有 init 函数; D. init 函数可以被其他函数调用; -
下面这段代码输出什么以及原因?
func hello() []string {
return nil
}
func main() {
h := hello
if h == nil {
fmt.Println("nil")
} else {
fmt.Println("not nil")
}
}
A. nil
B. not nil
C. compilation error
- 下面这段代码能否编译通过?如果可以,输出什么?
func GetValue() int {
return 1
}
func main() {
i := GetValue()
switch i.(type) {
case int:
println("int")
case string:
println("string")
case interface{}:
println("interface")
default:
println("unknown")
}
}
参考解析
- 参考答案及解析:AB。关于 init() 函数有几个需要注意的地方:
- init() 函数是用于程序执行前做包的初始化的函数,比如初始化包里的变量等;
- 一个包可以出线多个 init() 函数,一个源文件也可以包含多个 init() 函数;
- 同一个包中多个 init()函数的执行顺序没有明确定义,但是不同包的init函数是根据包导入的依赖关系决定的(看下图);
- init() 函数在代码中不能被显示调用、不能被引用(赋值给函数变量),否则出现编译错误;
- 一个包被引用多次,如 A import B,C import B,A import C,B 被引用多次,但 B 包只会初始化一次;
- 引入包,不可出现死循坏。即 A import B,B import A,这种情况编译失败;
- B。这道题目里面,是将 hello() 赋值给变量 h,而不是函数的返回值,所以输出 not nil。
- 编译失败。考点:类型选择,类型选择的语法形如:i.(type),其中 i 是接口,type 是固定关键字,需要注意的是,只有接口类型才可以使用类型选择。
Day9
-
关于channel,下面语法正确的是()
A. var ch chan int B. ch := make(chan int) C. <- ch D. ch <- -
下面这段代码输出什么?
type person struct {
name string
}
func main() {
var m map[person]int
p := person{"mike"}
fmt.Println(m[p])
}
A.0
B.1
C.Compilation error
- 下面这段代码输出什么?
func hello(num ...int) {
num[0] = 18
}
func main() {
i := []int{5, 6, 7}
hello(i...)
fmt.Println(i[0])
}
A.18
B.5
C.Compilation error
参考解析
-
ABC。A、B都是声明 channel;C 读取 channel;写 channel 是必须带上值,所以 D 错误。
-
A。打印一个 map 中不存在的值时,返回元素类型的零值。这个例子中,m 的类型是 map[person]int,因为 m 中不存在 p,所以打印 int 类型的零值,即 0。
-
18。知识点:可变函数
Day10
-
下面这段代码输出什么?
func main() { a := 5 b := 8.1 fmt.Println(a + b) }A.13.1 B.13 C.compilation error -
下面这段代码输出什么?
package main import ( "fmt" ) func main() { a := [5]int{1, 2, 3, 4, 5} t := a[3:4:4] fmt.Println(t[0]) }A.3 B.4 C.compilation error -
下面这段代码输出什么?
func main() { a := [2]int{5, 6} b := [3]int{5, 6} if a == b { fmt.Println("equal") } else { fmt.Println("not equal") } }A. compilation error B. equal C. not equal
参考解析
-
C。a 的类型是 int,b 的类型是 float,两个不同类型的数值不能相加,编译报错。
-
B。知识点:操作符 [i,j]。基于数组(切片)可以使用操作符 [i,j] 创建新的切片,从索引 i,到索引 j 结束,截取已有数组(切片)的任意部分,返回新的切片,新切片的值包含原数组(切片)的 i 索引的值,但是不包含 j 索引的值。i、j 都是可选的,i 如果省略,默认是 0,j 如果省略,默认是原数组(切片)的长度。i、j 都不能超过这个长度值。 假如底层数组的大小为 k,截取之后获得的切片的长度和容量的计算方法:长度:j-i,容量:k-i。
截取操作符还可以有第三个参数,形如 [i,j,k],第三个参数 k 用来限制新切片的容量,但不能超过原数组(切片)的底层数组大小。截取获得的切片的长度和容量分别是:j-i、k-i。
所以例子中,切片 t 为 [4],长度和容量都是 1。 详情参考 mp.weixin.qq.com/s/rLpJ3iOho…
-
A。Go 中的数组是值类型,可比较,另外一方面,数组的长度也是数组类型的组成部分,所以 a 和 b 是不同的类型,是不能比较的,所以编译错误。
Day11
-
关于 cap() 函数的适用类型,下面说法正确的是()
A. array B. slice C. map D. channel -
下面这段代码输出什么?
func main() { var i interface{} if i == nil { fmt.Println("nil") return } fmt.Println("not nil") }A. nil B. not nil C. compilation error -
下面这段代码输出什么?
func main() { s := make(map[string]int) delete(s, "h") fmt.Println(s["h"]) }A. runtime panic B. 0 C. compilation error
参考解析
- ABD。知识点:cap(),cap() 函数不适用 map。
- A。当且仅当接口的动态值和动态类型都为 nil 时,接口类型值才为 nil。参考link
- B。删除 map 不存在的键值对时,不会报错,相当于没有任何作用;获取不存在的减值对时,返回值类型对应的零值,所以返回 0。
Day12
-
下面属于关键字的是()
A.func B.struct C.class D.defer -
下面这段代码输出什么?
func main() { i := -5 j := +5 fmt.Printf("%+d %+d", i, j) }A. -5 +5 B. +5 +5 C. 0 0 -
下面这段代码输出什么?
type People struct{} func (p *People) ShowA() { fmt.Println("showA") p.ShowB() } func (p *People) ShowB() { fmt.Println("showB") } type Teacher struct { People } func (t *Teacher) ShowB() { fmt.Println("teacher showB") } func main() { t := Teacher{} t.ShowB() }
参考解析
-
ABD。知识点:Go 语言的关键字。Go 语言有 25 个关键字,看下图:
-
A。%d表示输出十进制数字,+表示输出数值的符号。这里不表示取反。
-
teacher showB。知识点:结构体嵌套。在嵌套结构体中,People 称为内部类型,Teacher 称为外部类型;通过嵌套,内部类型的属性、方法,可以为外部类型所有,就好像是外部类型自己的一样。此外,外部类型还可以定义自己的属性和方法,甚至可以定义与内部相同的方法,这样内部类型的方法就会被“屏蔽”。这个例子中的 ShowB() 就是同名方法。
关于结构体嵌套可以看看这篇文章。
Day13
-
定义一个包内全局字符串变量,下面语法正确的是()
A. var str string B. str := "" C. str = "" D. var str = "" -
下面这段代码输出什么?
func hello(i int) { fmt.Println(i) } func main() { i := 5 defer hello(i) i = i + 10 } -
下面这段代码输出什么?
type People struct{} func (p *People) ShowA() { fmt.Println("showA") p.ShowB() } func (p *People) ShowB() { fmt.Println("showB") } type Teacher struct { People } func (t *Teacher) ShowB() { fmt.Println("teacher showB") } func main() { t := Teacher{} t.ShowA() }
参考解析
- AD。B 只支持局部变量声明;C 是赋值,str 必须在这之前已经声明;
- 5。这个例子中,hello() 函数的参数在执行 defer 语句的时候会保存一份副本,在实际调用 hello() 函数时用,所以是 5.
-
结构体嵌套。这道题可以结合第 12 天的第三题一起看,Teacher 没有自己 ShowA(),所以调用内部类型 People 的同名方法,需要注意的是第 5 行代码调用的是 People 自己的 ShowB 方法。showA showB
Day14
- 下面代码输出什么?
func main() { str := "hello" str[0] = 'x' fmt.Println(str) }
A. hello B. xello C. compilation error
- 下面代码输出什么?
func incr(p *int) int { *p++ return *p } func main() { p :=1 incr(&p) fmt.Println(p) }
A. 1 B. 2 C. 3
- 对 add() 函数调用正确的是()
func add(args ...int) int { sum := 0 for _, arg := range args { sum += arg } return sum }
A. add(1, 2) B. add(1, 3, 7) C. add([]int{1, 2}) D. add([]int{1, 3, 7}…)
参考解析
- C。知识点:常量,Go 语言中的字符串是只读的。
- B。知识点:指针,incr() 函数里的 p 是 *int 类型的指针,指向的是 main() 函数的变量 p 的地址。第 2 行代码是将该地址的值执行一个自增操作,incr() 返回自增后的结果。
- ABD。知识点:可变函数
Day15
-
下面代码下划线处可以填入哪个选项?
func main() { var s1 []int var s2 = []int{} if __ == nil { fmt.Println("yes nil") }else{ fmt.Println("no nil") } }A. s1 B. s2 C. s1、s2 都可以
-
下面这段代码输出什么?
func main() { i := 65 fmt.Println(string(i)) }A. A B. 65 C. compilation error
-
下面这段代码输出什么?
type A interface { ShowA() int } type B interface { ShowB() int } type Work struct { i int } func (w Work) ShowA() int { return w.i + 10 } func (w Work) ShowB() int { return w.i + 20 } func main() { c := Work{3} var a A = c var b B = c fmt.Println(a.ShowA()) fmt.Println(b.ShowB()) }
参考解析
-
A。知识点:nil 切片和空切片。nil 切片和 nil 相等,一般用来表示一个不存在的切片;空切片和 nil 不相等,表示一个空的集合。
-
A。UTF-8 编码中,十进制数字 65 对应的符号是 A。
-
13 23。知识点:接口。一种类型实现多个接口,结构体 Work 分别实现了接口 A、B,所以接口变量 a、b 调用各自的方法 ShowA() 和 ShowB(),输出 13、23。
Day16
-
切片 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 两处应该怎么修改才能顺利编译?
func main() { var m map[string]int //A m["a"] = 1 if v := m["b"]; v != nil { //B fmt.Println(v) } } -
下面代码输出什么?
type A interface { ShowA() int } type B interface { ShowB() int } type Work struct { i int } func (w Work) ShowA() int { return w.i + 10 } func (w Work) ShowB() int { return w.i + 20 } func main() { c := Work{3} var a A = c var b B = c fmt.Println(a.ShowB()) fmt.Println(b.ShowA()) }A. 23 13 B. compilation error
参考解析
-
a、b、c 的长度和容量分别是 0 3、2 3、1 2。知识点:数组或切片的截取操作。截取操作有带 2 个或者 3 个参数,形如:[i:j] 和 [i:j:k],假设截取对象的底层数组长度为 l。在操作符 [i:j] 中,如果 i 省略,默认 0,如果 j 省略,默认底层数组的长度,截取得到的切片长度和容量计算方法是 j-i、l-i。操作符 [i:j:k],k 主要是用来限制切片的容量,但是不能大于数组的长度 l,截取得到的切片长度和容量计算方法是 j-i、k-i。
-
func main() { m := make(map[string]int) m["a"] = 1 if v,ok := m["b"]; ok { fmt.Println(v) } }在 A 处只声明了map m ,并没有分配内存空间,不能直接赋值,需要使用 make(),都提倡使用 make() 或者字面量的方式直接初始化 map。
B 处,v,k := m["b"] 当 key 为 b 的元素不存在的时候,v 会返回值类型对应的零值,k 返回 false。
-
B。知识点:接口的静态类型。a、b 具有相同的动态类型和动态值,分别是结构体 work 和 {3};a 的静态类型是 A,b 的静态类型是 B,接口 A 不包括方法 ShowB(),接口 B 也不包括方法 ShowA(),编译报错。看下编译错误:
a.ShowB undefined (type A has no field or method ShowB) b.ShowA undefined (type B has no field or method ShowA)
Day17
-
下面代码中,x 已声明,y 没有声明,判断每条语句的对错。
1.x, _ := f() 2.x, _ = f() 3.x, y := f() 4.x, y = f() -
下面代码输出什么?
func increaseA() int { var i int defer func() { i++ }() return i } func increaseB() (r int) { defer func() { r++ }() return r } func main() { fmt.Println(increaseA()) fmt.Println(increaseB()) }A. 1 1 B. 0 1 C. 1 0 D. 0 0
-
下面代码输出什么?
type A interface { ShowA() int } type B interface { ShowB() int } type Work struct { i int } func (w Work) ShowA() int { return w.i + 10 } func (w Work) ShowB() int { return w.i + 20 } func main() { var a A = Work{3} s := a.(Work) fmt.Println(s.ShowA()) fmt.Println(s.ShowB()) }A. 13 23 B. compilation error
参考解析
-
错、对、对、错。变量的声明。1.错,x 已经声明,不能使用:=;2.对;3.对,当多值赋值时,:= 左边的变量无论声明与否都可以;4.错,y 没有声明。
-
B。defer、返回值。注意一下,increaseA()的返回参数是匿名,increaseB()是具名。
-
A。类型断言。这道题可以和第 15 天的第三题 和第 16 天的第三题结合起来看,具体的解析看这里。
Day18
-
f1()、f2()、f3() 函数分别返回什么?
func f1() (r int) { defer func() { r++ }() return 0 } func f2() (r int) { t := 5 defer func() { t = t + 5 }() return t } func f3() (r int) { defer func(r int) { r = r + 5 }(r) return 1 }
参考解析
Day19
-
下面代码段输出什么?
type Person struct { age int } func main() { person := &Person{28} // 1. defer fmt.Println(person.age) // 2. defer func(p *Person) { fmt.Println(p.age) }(person) // 3. defer func() { fmt.Println(person.age) }() person.age = 29 }
参考解析
29 29 28。变量 person 是一个指针变量 。
1.person.age 此时是将 28 当做 defer 函数的参数,会把 28 缓存在栈中,等到最后执行该 defer 语句的时候取出,即输出 28;
2.defer 缓存的是结构体 Person{28} 的地址,最终 Person{28} 的 age 被重新赋值为 29,所以 defer 语句最后执行的时候,依靠缓存的地址取出的 age 便是 29,即输出 29;
3.闭包引用,输出 29;
又由于 defer 的执行顺序为先进后出,即 3 2 1,所以输出 29 29 28。
Day20
-
下面这段代码正确的输出是什么?
func f() { defer fmt.Println("D") fmt.Println("F") } func main() { f() fmt.Println("M") }A. F M D B. D F M C. F D M
-
下面代码输出什么?
type Person struct { age int } func main() { person := &Person{28} // 1. defer fmt.Println(person.age) // 2. defer func(p *Person) { fmt.Println(p.age) }(person) // 3. defer func() { fmt.Println(person.age) }() person = &Person{29} }
参考解析
-
C。被调用函数里的 defer 语句在返回之前就会被执行,所以输出顺序是 F D M。
-
29 28 28。这道题在第 19 天题目的基础上做了一点点小改动,前一题最后一行代码 person.age = 29 是修改引用对象的成员 age,这题最后一行代码 person = &Person{29} 是修改引用对象本身,来看看有什么区别。
1处.person.age 这一行代码跟之前含义是一样的,此时是将 28 当做 defer 函数的参数,会把 28 缓存在栈中,等到最后执行该 defer 语句的时候取出,即输出 28;
2处.defer 缓存的是结构体 Person{28} 的地址,这个地址指向的结构体没有被改变,最后 defer 语句后面的函数执行的时候取出仍是 28;
3处.闭包引用,person 的值已经被改变,指向结构体 Person{29},所以输出 29.
由于 defer 的执行顺序为先进后出,即 3 2 1,所以输出 29 28 28。
Day21
-
下面的两个切片声明中有什么区别?哪个更可取?
A. var a []int B. a := []int{} -
A、B、C、D 哪些选项有语法错误?
type S struct { } func f(x interface{}) { } func g(x *interface{}) { } func main() { s := S{} p := &s f(s) //A g(s) //B f(p) //C g(p) //D } -
下面 A、B 两处应该填入什么代码,才能确保顺利打印出结果?
type S struct { m string } func f() *S { return __ //A } func main() { p := __ //B fmt.Println(p.m) //print "foo" }
参考解析
-
A 声明的是 nil 切片;B 声明的是长度和容量都为 0 的空切片。第一种切片声明不会分配内存,优先选择。
-
BD。函数参数为 interface{} 时可以接收任何类型的参数,包括用户自定义类型等,即使是接收指针类型也用 interface{},而不是使用 *interface{}。
永远不要使用一个指针指向一个接口类型,因为它已经是一个指针。 -
A. &S{"foo"} B. *f() 或者 f()f() 函数返回参数是指针类型,所以可以用 & 取结构体的指针;B 处,如果填 *f(),则 p 是 S 类型;如果填 f(),则 p 是 *S 类型,不过都可以使用 p.m 取得结构体的成员。
Day22
-
下面的代码有几处语法问题,各是什么?
package main import ( "fmt" ) func main() { var x string = nil if x == nil { x = "default" } fmt.Println(x) } -
return 之后的 defer 语句会执行吗,下面这段代码输出什么?
var a bool = true func main() { defer func(){ fmt.Println("1") }() if a == true { fmt.Println("2") return } defer func(){ fmt.Println("3") }() }
参考解析
- go中只有引用类型才能和nil做比较或赋值为nil,go内置的引用类型只有三种:slice,map,channel,对于string的空值为""。
- 2 1。defer 关键字后面的函数或者方法想要执行必须先注册,return 之后的 defer 是不能注册的, 也就不能执行后面的函数或方法。
Day23
-
下面这段代码输出什么?为什么?
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) } -
下面选项正确的是?
func main() { if a := 1; false { } else if b := 2; false { } else { println(a, b) } }A. 1 2 B. compilation error
参考解析
-
golang 中切片底层的数据结构是数组。当使用 s1[1:] 获得切片 s2,和 s1 共享同一个底层数组,这会导致 s2[1] = 4 语句影响 s1。
而 append 操作会导致底层数组扩容,生成新的数组,因此追加数据后的 s2 不会影响 s1。
但是为什么对 s2 赋值后影响的却是 s1 的第三个元素呢?这是因为切片 s2 是从数组的第二个元素开始,s2 索引为 1 的元素对应的是 s1 索引为 2 的元素。
Day24
-
下面这段代码输出什么?
func main() { m := map[int]string{0:"zero",1:"one"} for k,v := range m { fmt.Println(k,v) } } -
下面这段代码输出什么?
func main() { a := 1 b := 2 defer calc("1", a, calc("10", a, b)) a = 0 defer calc("2", a, calc("20", a, b)) b = 1 } func calc(index string, a, b int) int { ret := a + b fmt.Println(index, a, b, ret) return ret }
参考解析
-
map 的输出是无序的。
-
10 1 2 3 20 0 2 2 2 0 2 2 1 1 3 4程序执行到 main() 函数三行代码的时候,会先执行 calc() 函数的 b 参数,即:calc("10",a,b),输出:10 1 2 3,得到值 3,因为 defer 定义的函数是延迟函数,故 calc("1",1,3) 会被延迟执行;
程序执行到第五行的时候,同样先执行 calc("20",a,b) 输出:20 0 2 2 得到值 2,同样将 calc("2",0,2) 延迟执行;
程序执行到末尾的时候,按照栈先进后出的方式依次执行:calc("2",0,2),calc("1",1,3),则就依次输出:2 0 2 2,1 1 3 4。
Day25
-
下面这段代码输出什么?为什么?
func (i int) PrintInt () { fmt.Println(i) } func main() { var i int = 1 i.PrintInt() }A. 1 B. compilation error
-
下面这段代码输出什么?为什么?
type People interface { Speak(string) string } type Student struct{} func (stu *Student) Speak(think string) (talk string) { if think == "speak" { talk = "speak" } else { talk = "hi" } return } func main() { var peo People = Student{} think := "speak" fmt.Println(peo.Speak(think)) }A. speak B. compilation error
参考解析
- B。基于类型创建的方法必须定义在同一个包内,上面的代码基于 int 类型创建了 PrintInt() 方法,由于 int 类型和方法 PrintInt() 定义在不同的包内,所以编译出错
- B。编译错误 Student does not implement People (Speak method has pointer receiver),值类型 Student 没有实现接口的 Speak() 方法,而是指针类型 *Student 实现该方法。
Day26
参考解析