GO·NOTE

一份 Go 开发工程师的学习笔记

0%

线上测试地址:https://play.studygolang.com/

TODO 第1题,

1、写出下面代码输出结果(20分)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
package main

import (
"fmt"
)

func main() {
defer_call()
}

func defer_call() {
defer func() { fmt.Println("打印前") }()
defer func() { fmt.Println("打印中") }()
defer func() { fmt.Println("打印后") }()

panic("触发异常")
}
参考答案 考点:defer执行顺序,panic的执行方式

结果:

1
2
3
4
打印后
打印中
“触发异常”
打印前

解析:“触发异常”可能出现在任何位置。defer是先进后出,逆序执行。
笔者猜测:panic()函数相当与go出去的一个协程,相关资料:https://blog.golang.org/defer-panic-and-recover, 将马上更新

2、以下代码有什么问题,说明原因(20分)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
type student struct {
Name string
Age int
}

func pase_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
}
}
参考答案

在range循环中,变量是不会随着遍历过程发生变化的。
因此在代码中stu是不会变化的,变化的是放在&stu地址上的数据,
因此最后m中value都将是最后一个放在&stu中的值

3、下面的代码会输出什么,并说明原因(20分)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
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()
}
参考答案

先说说WaitGroup的用途:它能够一直等到所有的goroutine执行完成,并且阻塞主线程的执行,直到所有的goroutine执行完成。
这里要注意一下,他们的执行结果是没有顺序的,调度器不能保证多个 goroutine 执行次序,且进程退出时不会等待它们结束。
WaitGroup总共有三个方法:Add(delta int),Done(),Wait()。简单的说一下这三个方法的作用。

  • Add:添加或者减少等待goroutine的数量
  • Done:相当于Add(-1)
  • Wait:执行阻塞,直到所有的WaitGroup数量变成0

4、下面代码会输出什么?(20分)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
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()
}
参考答案

首先明确一点 go中没有继承关系。也不应该提及“继承”这个词,其中Trecher并没有继承Propler,而是嵌套People,
而t.ShowA()是一个语法糖,其实t.ShowA() = t.people.ShowA(),也就是说在嵌套结构中,go会优先调用本身方法,
如果本身没有此方法,就回去调用其所包含结构的方法。

本题中,showA()是Teacher不具有的,但是它所嵌套的People具有,因此回调用People.showA(),People.showA()
中调用了*People 的showB()当然会展示“shwoB”,而不是“teacher showB”

引申一点,
如果嵌套有两个结构,并且两个结构具有相同的方法,如何执行的?
例如:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
type People struct{}

func (p *People) ShowA() {
fmt.Println("showA")
p.ShowB()
}
func (p *People) ShowB() {
fmt.Println("showB")
}

type Human struct{}

func (h *Human) ShowA() {
fmt.Println("Human showA")
}

type Teacher struct {
Human
People
}

func (t *Teacher) ShowB() {
fmt.Println("teacher showB")
}

func main() {
t := Teacher{}
t.ShowA()
}

答案是 编译报错,不支持这种情况的。

5、下面代码会触发异常吗?请详细说明(20分)

1
2
3
4
5
6
7
8
9
10
11
12
13
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)
}
}
参考答案

结果:

都可能发生

1
1
1
panic: hello

解析:

如果有一个或多个IO操作可以完成,则Go运行时系统会随机的选择一个执行,否则的话,如果有default分支,则执行default分支语句,如果连default都没有,则select语句会一直阻塞,直到至少有一个IO操作可以进行

比较容易复现的代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
package main

import (
"fmt"
"runtime"
)

func main() {
runtime.GOMAXPROCS(1)
int_chan := make(chan int, 100)
string_chan := make(chan string, 100)

for i:=0;i<100;i++{
int_chan <- i
string_chan <- fmt.Sprintf("hello-%d",i)
}

for {
select {
case value := <-int_chan:
fmt.Println(value)
case value := <-string_chan:
panic(value)
}
}
}

参考文档

https://www.jianshu.com/p/2a1146dc42c3

6、下面代码会输出什么?(20分)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
func calc(index string, a, b int) int {
ret := a + b
fmt.Println(index, a, b, ret)
return ret
}

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
}
参考答案

结果:

1
2
3
4
10 1 2 3
20 0 2 2
2 0 2 2
1 1 3 4

解析:

1、当程序运行到defer函数时,不会执行函数实现,但会将defer函数中的参数代码进行执行。
因此首先执行的是calc(“10”, a, b)),随后执行的是calc(“2”, a, calc(“20”, a, b))
得到第一行和第二行结果。

2、defer的执行结果是先进后出,从函数尾部向函数头部以此执行。因此会首先执行calc(“2”, a, calc(“20”, a, b)),
然后执行defer calc(“1”, a, calc(“10”, a, b)),相应打印第三行和第四行

7、请写出以下输出内容(20分)

1
2
3
4
5
func main() {
s := make([]int, 5)
s = append(s, 1, 2, 3)
fmt.Println(s)
}
参考答案

结果:

1
0 0 0 0 0 1 2 3

解析:

make([]int,5)的含义是创建数组,并且数组初始化5个元素,5个元素的值为类型零值。

8、下面的代码有什么问题(20分)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
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
}
参考答案

结果:

1
fatal error: concurrent map read and map write

解析:

map 是并发不安全的,不能同时读写,为了复现,将代码改为以下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
package main

import (
"fmt"
"sync"
"time"
)

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
}

func main() {
ua := new(UserAges)
ua.ages = make(map[string]int)

for i:=0;i<1000;i++ {

go func(i int) {
ua.Add(fmt.Sprintf("student-%d",i),i)
}(i)
}

for i:=0;i<1000;i++{

go func(i int) {
fmt.Println(ua.Get(fmt.Sprintf("student-%d",i)))
}(i)
}

time.Sleep(10 * time.Second)
}

9、实现一个并发安全的set(20分)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
package main

import (
"fmt"
"sync"
"time"
)

type threadSafeSet struct {
sync.RWMutex
data map[interface{}]interface{}
}

func (set *threadSafeSet)Add(item interface{}) {
// map is not safe in concurrency
set.Lock()
set.data[item] = true
set.Unlock()
}

func (set *threadSafeSet)Remove(item interface{}) {
set.Lock()
delete(set.data,item)
set.Unlock()
}

func (set *threadSafeSet) Iter() <-chan interface{} {
ch := make(chan interface{})
go func() {
set.RLock()
for item,_ := range set.data {
ch <- item
}
close(ch)
set.RUnlock()

}()
return ch
}

func main() {
set := new(threadSafeSet)
set.data = make(map[interface{}]interface{})
for i:=0;i<10 ;i++ {
set.Add(i)
}

for item := range set.Iter(){
fmt.Printf("get value from set,value is %v\n",item)
}

time.Sleep(5 * time.Second)
}
参考答案

等待更新…

10、以下代码能编译过去吗?为什么?(20分)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
package main

import (
"fmt"
)

type People interface {
Speak(string) string
}

type Student struct{}

func (stu *Student) Speak(think string) (talk string) {
if think == "bitch" {
talk = "You are a good boy"
} else {
talk = "hi"
}
return
}

func main() {
var peo People = Student{}
think := "bitch"
fmt.Println(peo.Speak(think))
}
参考答案

结果:

1
编译不过去

解析:

原因是Student并没有继承People,people中有Speak(string)string方法,而Student类型中没有Speak()方法,
代码中的Student方法是*Student类型的,所有 var peo People = Student{}是不符合规范的。

线上测试地址:https://play.studygolang.com/

未解析:第一题、第七题

1、以下代码打印出来什么内容,说出为什么?(20分)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
package main

import (
"fmt"
)

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")
}
}
参考答案

结果:

1
BBBBBBB

解析:

interface 的结构为以下两种的其中一个,代码中将 nil的*student 赋值给 People接口类型,其实为:people.Data = nil。但是people不为nil。

1
2
3
4
5
6
7
8
9
type iface struct { 
tab *itab
data unsafe.Pointer
}

type eface struct {
_type *_type
data unsafe.Pointer
}

解决方案:

1、知道类型的情况下,自然是可以使用类型断言后判空。如ai, ok := i.(*int),之后判断ai == nil。

2、不知道是何种类型的指针,就只好借助反射了vi := reflect.ValueOf(i),后使用vi.IsNil()来判断。但如果i里放到不是一个指针,调用IsNil会出异常,则可能要写一个这样的函数来判空

1
2
3
4
5
6
7
func IsNil(i interface{}) bool {
defer func() {
recover()
}()
vi := reflect.ValueOf(i)
return vi.IsNil()
}

但有这样强加一个defer的recover确实不好看,于是借助类型判断变成这样

1
2
3
4
5
6
7
func IsNil(i interface{}) bool {
vi := reflect.ValueOf(i)
if vi.Kind() == reflect.Ptr {
return vi.IsNil()
}
return false
}

参考文章:

https://www.jianshu.com/p/97bfe8104e03
https://www.cnblogs.com/chenqionghe/p/11357013.html
https://blog.csdn.net/lanyang123456/article/details/83715090

2.是否可以编译通过?如果通过,输出什么?(20分)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
func main() {
i := GetValue()

switch i.(type) {
case int:
println("int")
case string:
println("string")
case interface{}:
println("interface")
default:
println("unknown")
}

}

func GetValue() int {
return 1
}
参考答案

结果:

1
cannot type switch on non-interface value i (type *string)

解析:

两点规则:

1、golang中x.(type)语句,只能在 switch case中使用。类似:

1
2
3
4
5
6
7
8
9
10
switch i.(type) {
case int:
println("int")
case string:
println("string")
case interface{}:
println("interface")
default:
println("unknown")
}

2、x.(type)必须为 interface 类型,否则会编译报错,因为如果不是 interface,也没有.(type)的必要。

参考文档:

https://my.oschina.net/robin3d/blog/1862756

3.下面函数有什么问题?(20分)

1
2
3
func funcMui(x,y int)(sum int,error){
return x+y,nil
}
参考答案

结果:

1
Function has both named and unnamed return parameters '(sum int,error)'

解析:

函数的返回值,要么都被定义名称,要不都不定义。其中 int 类型定义了,error却没有定义

4.是否可以编译通过?如果通过,输出什么?(20分)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
package main

func main() {

println(DeferFunc1(1))
println(DeferFunc2(1))
println(DeferFunc3(1))
}

func DeferFunc1(i int) (t int) {
t = i
defer func() {
t += 3
}()
return t
}

func DeferFunc2(i int) int {
t := i
defer func() {
t += 3
}()
return t
}

func DeferFunc3(i int) (t int) {
defer func() {
t += i
}()
return 2
}}

5.是否可以编译通过?如果通过,输出什么?(20分)

1
2
3
4
5
func main() {
list := new([]int)
list = append(list, 1)
fmt.Println(list)
}
参考答案

结果:

1
first argument to append must be slice; have *[]int

解析:

题目中 list 为数组指针,而非 slice,不具有 append 方法

new(T) 为每个新的类型T分配一片内存,初始化为 0 并且返回类型为*T的内存地址:这种方法 返回一个指向类型为 T,值为 0 的地址的指针,它适用于值类型如数组和结构体;它相当于 &T{}。

make(T) 返回一个类型为 T 的初始值,它只适用于3种内建的引用类型:slice、map 和 channel。

换言之,new 函数分配内存,make 函数初始化;

6.是否可以编译通过?如果通过,输出什么?(20分)

1
2
3
4
5
6
7
8
9
10
package main

import "fmt"

func main() {
s1 := []int{1, 2, 3}
s2 := []int{4, 5}
s1 = append(s1, s2)
fmt.Println(s1)
}
参考答案

结果:

1
.\test.go:8:13: cannot use s2 (type []int) as type int in append

解析:

1
func append(slice []Type, elems ...Type) []Type

apend 函数接受的是可变长参数。题目中s2为[]int类型,非可变长参数。s2…为可变长。
... 将 s2 变为可变长参数。

扩展:

的用法主要有以下两种:

第一个用法主要是用于函数有多个不定参数的情况,可以接受多个不确定数量的参数。
第二个用法是slice可以被打散进行传递。

7.是否可以编译通过?如果通过,输出什么?(20分)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
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")
}
}
参考答案

结果:

1
.\test.go:29:9: invalid operation: sm1 == sm2 (struct containing map[string]string cannot be compared)

解析:

暂无解析

8.是否可以编译通过?如果通过,输出什么?(20分)

1
2
3
4
5
6
7
8
9
10
11
func Foo(x interface{}) {
if x == nil {
fmt.Println("empty interface")
return
}
fmt.Println("non-empty interface")
}
func main() {
var x *int = nil
Foo(x)
}
参考答案

同第一题

9.是否可以编译通过?如果通过,输出什么?(20分)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
func GetValue(m map[int]string, id int) (string, bool) {
if _, exist := m[id]; exist {
return "存在数据", true
}
return nil, false
}
func main() {
intmap := map[int]string{
1:"a",
2:"bb",
3:"ccc",
}

v,err := GetValue(intmap,3)
fmt.Println(v,err)
}
参考答案

结果:

1
cannot use nil as type string in return argument

解析:

string 不可定义为nil,它的零值为””,可以定义为 nil 的类型只有以下几种:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
package main

import (
"fmt"
)

type Student struct {}

func main() {

var sli []int = nil
var c chan int = nil
var m map[string]string = nil
var stu *Student = nil
var i interface{} = nil

fmt.Println(sli,c,m,stu,i)
}
1
[] <nil> map[] <nil> <nil>

10.是否可以编译通过?如果通过,输出什么?(20分)

1
2
3
4
5
6
7
8
9
10
11
const (
x = iota
y
z = "zz"
k
p = iota
)

func main() {
fmt.Println(x,y,z,k,p)
}
参考答案

结果:

1
0 1 zz zz 4

解析:

iota是golang语言的常量计数器,只能在常量的表达式中使用。

iota在const关键字出现时将被重置为0,const中每新增一行常量声明将使iota计数一次。

使用方法:

  1. iota只能在常量的表达式中使用
1
2
fmt.Println(iota)
编译错误: undefined: iota
  1. 每次 const 出现时,都会让 iota 初始化为0
1
2
3
4
5
const a = iota    // a=0
const (
    b = iota     //b=0
    c            //c=1
)
  1. 自定义类型,自增长常量经常包含一个自定义枚举类型,允许你依靠编译器完成自增设置
1
2
3
4
5
6
7
type status int
const (
    unknow status = iota    // 0
    queued                  // 1
    queued                  // 2
    queued                  // 3
)
  1. 可跳过的值
1
2
3
4
5
6
7
8
9
type status int
const (
    unknow status = iota     // 0
    queued                   // 1
    queued                   // 2
    _
    _
    queued                   // 5
)
  1. 定义在一行的情况
1
2
3
4
5
6
7
8
9
10
11
12
const (
    a, b = iota + 1, iota + 2
    c, d
    e, f
)

a //1
b //2
c //2
d //3
e //3
f //4

6、中间插队且下个变量没有赋值时,下个变量会和上个变量一样。iota自动加1

1
2
3
4
5
6
7
8
9
const (
x = iota
y
z = "zz"
k
p = iota
)

0 1 zz zz 4

线上测试地址:https://play.studygolang.com/

1、下面代码能运行吗?为什么?(20分)

1
2
3
4
5
6
7
8
9
10
type Param map[string]interface{}

type Show struct {
Param
}

func main1() {
s := new(Show)
s.Param["RMB"] = 10000
}
参考答案

结果:

1
2
3
4
5
panic: assignment to entry in nil map

goroutine 1 [running]:
main.main()
/tmp/sandbox845633960/prog.go:11 +0x40

map、slic、channel 需要初始化才可以使用,
题目中中的s.Param 并没有进行初始化。

2.请说出下面代码存在什么问题?(20分)

1
2
3
4
5
6
7
8
9
10
type student struct {
Name string
}

func zhoujielun(v interface{}) {
switch msg := v.(type) {
case *student, student:
msg.Name
}
}
参考答案

结果:

1
./prog.go:10:6: msg.Name undefined (type interface {} is interface with no methods)

解析:

msg.Name 不是方法,不可单独使用。

3.写出打印的结果?(20分)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
type People struct {
name string `json:"name"`
}

func main() {
js := `{
"name":"11"
}`
var p People
err := json.Unmarshal([]byte(js), &p)
if err != nil {
fmt.Println("err: ", err)
return
}
fmt.Println("people: ", p)
}
参考答案

结果:

1
people:  {}

解析:

这个是因为 People struct 的字段 name 为小写,不能被外部包使用,所以json.Unmarshal()时,json包不可以进行映射。

1
./prog.go:9:2: struct field name has json tag but is not exported

4.下面的代码有问题吗?(20分)

1
2
3
4
5
6
7
8
9
10
11
12
type People struct {
Name string
}

func (p *People) String() string {
return fmt.Sprintf("print: %v", p)
}

func main() {
p := &People{}
p.String()
}
参考答案

结果:

1
2
runtime: goroutine stack exceeds 250000000-byte limit
fatal error: stack overflow

解析:

fmt.Sprintf(“print: %v”, p) 会调用p.String()方法,造成循环调用,引起栈溢出。

5.下面代码有没有问题,有的话问题在哪里?(20分)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
func main() {
ch := make(chan int, 1000)
go func() {
for i := 0; i < 10; i++ {
ch <- i
}
}()
go func() {
for {
a, ok := <-ch
if !ok {
fmt.Println("close")
return
}
fmt.Println("a: ", a)
}
}()
close(ch)
fmt.Println("ok")
time.Sleep(time.Second * 100)
}
参考答案

等待更新…

6.请说明下面代码书写是否正确?(20分)

1
2
3
4
5
6
7
8
9
10
var value int32

func SetValue(delta int32) {
for {
v := value
if atomic.CompareAndSwapInt32(&value, v(v+delta)) {
break
}
}
}
参考答案

等待更新…

7.下面的程序运行后为什么会爆异常?(20分)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
type Project struct{}

func (p *Project) deferError() {
if err := recover(); err != nil {
fmt.Println("recover: ", err)
}
}

func (p *Project) exec(msgchan chan interface{}) {
for msg := range msgchan {
m := msg.(int)
fmt.Println("msg: ", m)
}
}

func (p *Project) run(msgchan chan interface{}) {
for {
defer p.deferError()
go p.exec(msgchan)
time.Sleep(time.Second * 2)
}
}

func (p *Project) Main() {
a := make(chan interface{}, 100)
go p.run(a)
go func() {
for {
a <- "1"
time.Sleep(time.Second)
}
}()
time.Sleep(time.Second * 100000000000000)
}

func main() {
p := new(Project)
p.Main()
}
参考答案

等待更新…

8.下面的代码有没有错误,有的话错在哪里?(20分)

1
2
3
4
5
6
7
8
9
10
11
func Foo(x interface{}) {
if x == nil {
fmt.Println("empty interface")
return
}
fmt.Println("non-empty interface")
}
func main() {
var x *int = nil
Foo(x)
}
参考答案

等待更新…

9.请说出下面代码,执行时为什么会报错?(20分)

1
2
3
4
5
6
7
8
type Student struct {
name string
}

func main() {
m := map[string]Student{"people": {"zhoujielun"}}
m["people"].name = "wuyanzu"
}
参考答案

结果:

1
./prog.go:9:19: cannot assign to struct field m["people"].name in map

解析:

原因是 map 元素是无法取址的,也就说可以得到 m[“people”], 但是无法对其进行修改。

解决办法:使用指针的map,map[string]*Student

10.请说出下面的代码存在什么问题?(20分)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
type query func(string) string

func exec(name string, vs ...query) string {
ch := make(chan string)
fn := func(i int) {
ch <- vs[i](name)
}
for i, _ := range vs {
go fn(i)
}
return <-ch
}

func main() {
ret := exec("111", func(n string) string {
return n + "func1"
}, func(n string) string {
return n + "func2"
}, func(n string) string {
return n + "func3"
}, func(n string) string {
return n + "func4"
})
fmt.Println(ret)
}
参考答案

等待更新…