1、写出下面代码输出内容。
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: 触发异常
考察对defer的理解,defer函数属延迟执行,延迟到调用者函数执行 return 命令前被执行。多个defer之间按LIFO先进后出顺序执行。
故考题中,在Panic触发时结束函数运行,在return前先依次打印:打印后、打印中、打印前 。最后由runtime运行时抛出打印panic异常信息。
2 下面代码有啥问题
package main
import (
"fmt"
)
type student struct {
Name string
Age int
}
func pase_student() map[string]*student {
m := make(map[string]*student)
stus := []student{
{Name: "zhou", Age: 24},
{Name: "li", Age: 23},
{Name: "wang", Age: 22},
}
for _, stu := range stus {
m[stu.Name] = &stu
}
return m
}
func main() {
students := pase_student()
for k, v := range students {
fmt.Printf("key=%s,value=%v \n", k, v)
}
}
答:输出的均是相同的值:&{wang 22}
解析 因为for遍历时,变量stu指针不变,每次遍历仅进行struct值拷贝,故m[stu.Name]=&stu实际上一致指向同一个指针,最终该指针的值为遍历的最后一个struct的值拷贝。形同如下代码:
3.下面代码会输出啥
func main() {
runtime.GOMAXPROCS(1)
wg := sync.WaitGroup{}
wg.Add(20)
for i := 0; i < 10; i++ {
go func() {
fmt.Println("i: ", i)
wg.Done()
}()
}
for i := 0; i < 10; i++ {
go func(i int) {
fmt.Println("i: ", i)
wg.Done()
}(i)
}
wg.Wait()
}
答: 将随机输出数字,但前面一个循环中并不会输出所有值。
解析:
实际上第一行是否设置CPU为1都不会影响后续代码。
2017年7月25日:将GOMAXPROCS设置为1,将影响goroutine的并发,后续代码中的go func()相当于串行执行。
两个for循环内部go func 调用参数i的方式是不同的,导致结果完全不同。这也是新手容易遇到的坑。
第一个go func中i是外部for的一个变量,地址不变化。遍历完成后,最终i=10。故go func执行时,i的值始终是10(10次遍历很快完成)。
第二个go func中i是函数参数,与外部for中的i完全是两个变量。尾部(i)将发生值拷贝,go func内部指向值拷贝地址。
4 下面代码输出啥
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()
}
showA
showB
Go中没有继承! 没有继承!没有继承!是叫组合!组合!组合!
ShowA()
这里仍然是People。毕竟这个People类型并不知道自己会被什么类型组合,当然也就无法调用方法时去使用未知的组合者Teacher类型的功能。
因此这里执行t.ShowA()时,在执行ShowB()时该函数的接受者是People,而非Teacher
5.下面代码会触发异常吗?请详细说明
func main() {
runtime.GOMAXPROCS(1)
int_chan := make(chan int, 1)
string_chan := make(chan string, 1)
int_chan <- 1
string_chan <- "hello"
select {
case value := <-int_chan:
fmt.Println(value)
case value := <-string_chan:
panic(value)
}
}
答: 有可能触发异常,是随机事件。
解析
单个chan如果无缓冲时,将会阻塞。但结合 select可以在多个chan间等待执行。有三点原则:
select 中只要有一个case能return,则立刻执行。
当如果同一时间有多个case均能return则伪随机方式抽取任意一个执行。
如果没有一个case能return则可以执行”default”块。
此考题中的两个case中的两个chan均能return,则会随机执行某个case块。故在执行程序时,有可能执行第二个case,
下面代码输出啥 考关于defer 3个小练习
func calc(index string, a, b int) int {
ret := a + b
fmt.Println(index, a, b, ret)
return ret
}
func main() {
a := 1 //line 1
b := 2 //2
defer calc("1", a, calc("10", a, b)) //3
a = 0 //4
defer calc("2", a, calc("20", a, b)) //5
b = 1 //6
}
// 1.a:=1
// 2.b:=2
// 3.defer calc ("1",1,calc("10",1,2))
//4.calc("10",1,2) 执行结果为 "10",1,2 3
//5.defer calc ("1",1,3)
//6.a=0
//7.defer calc("2",0,calc("20",0,2))
//8.calc("20",0,2) 执行结果为 "20",0,2 2
//9.defer calc("2",0,2)
//10.b=1
//11.defer 先进后出
//12.defer calc("2",0,2) 执行结果为 "2",0,2 2
//13.defer calc ("1",1,3) 执行结果为 “1” 1,3 4
答 输出结果为:
10 1 2 3
20 0 2 2
2 0 2 2
1 1 3 4
func f1() int {
x := 5
defer func() {
x++
}()
return x
}
func f2() (x int) {
defer func() {
x++
}()
return 5
}
func f3() (y int) {
x := 5
defer func() {
x++
}()
return x
}
func f4() (x int) {
defer func(x int) {
x++
}(x)
return 5
}
func main() {
fmt.Println(f1())
fmt.Println(f2())
fmt.Println(f3())
fmt.Println(f4())
}
5
6
5
5
func calc(index string, a, b int) int {
ret := a + b
fmt.Println(index, a, b, ret)
return ret
}
func main() {
x := 1
y := 2
defer calc("AA", x, calc("A", x, y))
x = 10
defer calc("BB", x, calc("B", x, y))
y = 20
}
//1.x:=1
//2.y:=2
//3.defer calc ("AA",1,calc("A",1,2))
//4. calc("A",1,2) 执行里面的结果为 "A" 1,2,3
//5. defer calc ("AA",1,3)
//6.x=10
// 7.defer calc("BB",10,calc("B",10,2))
//8. calc("B",10,2) 取里面的 执行结果为 "B" 10 2 12
//9.defer calc ("BB",10,12)
//10.Y=20
//11. defer先进后出的原则
//12.defer calc ("BB",10,12) 执行结果为 “BB” 10 12 22
//13.defer calc ("AA",1,3) 执行结果为 “AA” 1 3 4
A 1 2 3
B 10 2 12
BB 10 12 22
AA 1 3 4
7、请写出以下输入内容
func main() {
s := make([]int, 5)
s = append(s, 1, 2, 3)
fmt.Println(s)
}
将输出:[0 0 0 0 0 1 2 3]
make([]int,5)[0,0,0,0,0]append(s,1,2,3)[0 0 0 0 0 1 2 3]
8下面的代码有什么问题?
type UserAges struct {
ages map[string]int
sync.Mutex
}
func (ua *UserAges) Add(name string, age int) {
ua.Lock()
defer ua.Unlock()
ua.ages[name] = age
}
func (ua *UserAges) Get(name string) int {
if age, ok := ua.ages[name]; ok {
return age
}
return -1
}
9.下面的迭代会有什么问题?
unc (set *threadSafeSet) Iter() <-chan interface{} {
ch := make(chan interface{})
go func() {
set.RLock()
for elem := range set.s {
ch <- elem
}
close(ch)
set.RUnlock()
}()
return ch
}
内部迭代出现阻塞。默认初始化时无缓冲区,需要等待接收者读取后才能继续写入。
解析
chan在使用make初始化时可附带一个可选参数来设置缓冲区。默认无缓冲,题目中便初始化的是无缓冲区的chan,这样只有写入的元素直到被读取后才能继续写入,不然就一直阻塞。
设置缓冲区大小后,写入数据时可连续写入到缓冲区中,直到缓冲区被占满。从chan中接收一次便可从缓冲区中释放一次。可以理解为chan是可以设置吞吐量的处理池。
10、以下代码能编译过去吗?为什么?
package main
import (
"fmt"
)
type People interface {
Speak(string) string
}
type Stduent struct{}
func (stu *Stduent) Speak(think string) (talk string) {
if think == "bitch" {
talk = "You are a good boy"
} else {
talk = "hi"
}
return
}
func main() {
var peo People = Stduent{}
think := "bitch"
fmt.Println(peo.Speak(think))
}
func (stu *Stduent) Speak(think string) (talk string)*StudentStudentgo var peo People = &Stduent{}go func (stu Stduent) Speak(think string) (talk string) { //... }
11.
type People interface {
Show()
}
type Student struct{}
func (stu *Student) Show() {
}
func live() People {
var stu *Student
return stu
}
func main() {
if live() == nil {
fmt.Println("AAAAAAA")
} else {
fmt.Println("BBBBBBB")
}
}
这个打印bbbb