Golang 面试题

以下代码有什么问题,说明原因

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

}
  • 解析
    • foreach 解答
    • 这样的写法初学者经常会遇到的,很危险! 与Java的foreach一样,都是使用副本的方式。所以m[stu.Name]=&stu实际上一致指向同一个指针, 最终该指针的值为遍历的最后一个struct的值拷贝。 就像想修改切片元素的属性

下面代码会输出什么?

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的组合继承 解答: 这是Golang的组合模式,可以实现OOP的继承。 被组合的类型People所包含的方法虽然升级成了外部类型Teacher这个组合类型的方法(一定要是匿名字段),但它们的方法(ShowA())调用时接受者并没有发生变化。 此时People类型并不知道自己会被什么类型组合,当然也就无法调用方法时去使用未知的组合者Teacher类型的功能。
1
2
showA
showB

下面代码输出什么?

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
}
  • 考点:defer执行顺序 解答: 这道题类似第1题 需要注意到defer执行顺序和值传递 index:1肯定是最后执行的,但是index:1的第三个参数是一个函数,所以最先被调用calc(“10”,1,2)==>10,1,2,3 执行index:2时,与之前一样,需要先调用calc(“20”,0,2)==>20,0,2,2 执行到b=1时候开始调用,index:2==>calc(“2”,0,2)==>2,0,2,2 最后执行index:1==>calc(“1”,1,3)==>1,1,3,4
1
2
3
4
10 1 2 3
20 0 2 2
2 0 2 2
1 1 3 4

是否可以编译通过?如果通过,输出什么?

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
}
  • 解析
    • 考点:type
    • 编译失败,因为type只能使用在interface

以下代码有什么问题,说明原因

1
2
3
4
5
func main() {
list := new([]int)
list = append(list, 1)
fmt.Println(list)
}
  • 解析
    • 不可以通过
    • append返回的是( []int ),而list是( *[]int )
    • 可以用 list:=make([]int,0) 代替声明

是否可以编译通过?如果通过,输出什么?

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
    2
    3
    4
    sn3:= struct {
    name string
    age int
    }{age:11,name:"qq"}
  • sn3与sn1就不是相同的结构体了,不能比较。 还有一点需要注意的是结构体是相同的,但是结构体属性中有不可以比较的类型,如map,slice。 如果该结构属性都是可以比较的,那么就可以使用“==”进行比较操作。
  • 可以使用reflect.DeepEqual进行比较
    1
    2
    3
    4
    5
    if reflect.DeepEqual(sn1, sm) {
    fmt.Println("sn1 ==sm")
    }else {
    fmt.Println("sn1 !=sm")
    }
  • 所以编译不通过: invalid operation: sm1 == sm2

是否可以编译通过?如果通过,输出什么

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)
}
  • 考点:iota 结果
    1
    0 1 zz zz 4

下面函数有什么问题

1
2
3
4
5
6
7
8
9
package main
const cl = 100

var bl = 123

func main() {
println(&bl,bl)
println(&cl,cl)
}
  • 考点:常量
    • 常量不同于变量的在运行期分配内存,常量通常会被编译器在预处理阶段直接展开,作为指令数据使用
1
cannot take the address of cl