Golang面试题,收集自Golang中文网,收集是为了自己可以巩固复习,不必要每次去找
Golang面试题,收集自Golang中文网,收集是为了自己可以巩固复习,不必要每次去找
目录
- 1. 下面这段代码输出的内容:
- 2. 下面这段代码输出什么,说明原因。
- 3. 下面两段代码输出什么?
- 4. 下面这段代码有什么缺陷?
- 5. new() 与 make() 的区别
- 6. 下面这段代码能否通过编译,不能的话原因是什么;如果能,输出什么?
- 7. 下面这段代码能否通过编译,不能的话原因是什么;如果可以,输出什么?
- 8. 下面这段代码能否通过编译,如果可以,输出什么?
- 9. 下面这段代码能否通过编译?不能的话,原因是什么?如果通过,输出什么?
- 10. 通过指针变量p访问其成员变量name,有哪几种方式?
- 11. 下面这段代码能否通过编译?如果通过,输出什么?
- 12. 以下代码输出什么?
- 13. 关于字符串连接,下面语法正确的是?
- 14. 下面这段代码能否编译通过?如果可以,输出什么?
- 15. 下面赋值正确的是()
- 16. 关于init函数,下面说法正确的是()
- 17. 下面这段代码输出什么以及原因?
- 18. 下面这段代码能否编译通过?如果可以,输出什么?
- 19. 关于channel,下面语法正确的是()
- 20. 下面这段代码输出什么?
- 21. 下面这段代码输出什么?
- 22. 下面这段代码输出什么?
- 23. 下面这段代码输出什么?
- 24. 下面这段代码输出什么?
- 25. 关于 cap() 函数的适用类型,下面说法正确的是()
- 26. 下面这段代码输出什么?
- 27. 下面这段代码输出什么?
- 28. 下面属于关键字的是()
- 29. 下面这段代码输出什么?
- 30. 下面这段代码输出什么?
- 31. 31-60题
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 的执行顺序是先进后出。出现panic语句的时候,会先按照 defer 的后进先出顺序执行,最后才会执行panic。
package main
import "fmt"
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)
}
}答:输出内容为:
// 注:key的顺序无法确定
0 -> 3
1 -> 3
2 -> 3
3 -> 3解析:
for range 循环的时候会创建每个元素的副本,而不是每个元素的引用,所以 m[key] = &val 取的都是变量val的地址,所以最后 map 中的所有元素的值都是变量 val 的地址,因为最后 val 被赋值为3,所有输出的都是3。
// 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)
}答:输出内容为:
// 1.
[0 0 0 0 0 1 2 3]
// 2.
[1 2 3 4]解析:
使用 append 向 slice 中添加元素,第一题中slice容量为5,所以补5个0,第二题为0,所以不需要。
func funcMui(x, y int) (sum int, error) {
return x + y, nil
}答:第二个返回值没有命名
解析:
在函数有多个返回值时,只要有一个返回值有命名,其他的也必须命名。如果有多个返回值必须加上括号();如果只有一个返回值且命名也需要加上括号()。这里的第一个返回值有命名sum,第二个没有命名,所以错误。
解析:
new(T) 和 make(T, args) 是Go语言内建函数,用来分配内存,但适用的类型不用。new(T) 会为了 T 类型的新值分配已置零的内存空间,并返回地址(指针),即类型为 *T 的值。换句话说就是,返回一个指针,该指针指向新分配的、类型为 T 的零值。适用于值类型,如 数组 、 结构体 等。make(T, args) 返回初始化之后的T类型的值,也不是指针 *T ,是经过初始化之后的T的引用。 make() 只适用于 slice 、 map 和 channel 。func main() {
list := new([]int)
list = append(list, 1)
fmt.Println(list)
}答:不能通过
解析:
不能通过编译, new([]int) 之后的 list 是一个 *int[] 类型的指针,不能对指针执行 append 操作。可以使用 make() 初始化之后再用。同样的, map 和 channel 建议使用 make() 或字面量的方式初始化,不要用 new 。
func main() {
s1 := []int{1, 2, 3}
s2 := []int{4, 5}
s1 = append(s1, s2)
fmt.Println(s1)
}答:不能通过
解析:
append() 的第二个参数不能直接使用 slice ,需使用 ... 操作符,将一个切片追加到另一个切片上: append(s1, s2...) 。或者直接跟上元素,形如: append(s1, 1, 2, 3) 。
var (
size := 1024
max_size = size * 2
)
func main() {
fmt.Println(size, max_size)
}答:不能通过
解析:
这道题的主要知识点是变量的简短模式,形如:x := 100 。但这种声明方式有限制:
func main() {
sn1 := struct {
age int
name string
}{age: 11, name: "qq"}
sn2 := struct {
age int
name string
}{age: 11, name: "11"}
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
解析:
考点是结构体的比较,有几个需要注意的地方:
那有什么是可以比较的呢?
不能比较的有
答:A C
解析:
& 取址运算符, * 指针解引用
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)
}答:不能通过
解析:
这道题考的是 类型别名 与 类型定义 的区别
第5行代码是基于类型 int 创建了新类型 MyInt1 ,第6行代码是创建了int的类型别名 MyInt2 ,注意类型别名的定义是 = 。所以,第10行代码相当于是将int类型的变量赋值给MyInt1类型的变量,Go是强类型语言,编译当然不通过;而MyInt2只是int的别名,本质上还是int,可以赋值。
第10行代码的赋值可以使用强制类型转换 var i1 MyInt1 = MyInt1(i)
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导致底层数组重新分配内存了,append中的a这个alice的底层数组和外面不是一个,并没有改变外面的。
答:B、D
解析:
在Golang中字符串用双引号,字符用单引号
字符串连接除了以上两种连接方式,还有 strings.Join() 、 buffer.WriteString() 等
const (
x = iota
_
y
z = "zz"
k
p = iota
)
func main() {
fmt.Println(x, y, z, k, p)
}答:编译通过,输出:**0 2 zz zz 5**
解析:
iota初始值为0,所以x为0,_表示不赋值,但是iota是从上往下加1的,所以y是2,z是“zz”,k和上面一个同值也是“zz”,p是iota,从上0开始数他是5
答:B、D
解析:
A错在没有写类型,C错在字符串的空值是 "" 而不是nil。
知识点:nil只能赋值给指针、chan、func、interface、map、或slice、类型的变量。
答:A、B
解析:
func hello() []string {
return nil
}
func main() {
h := hello
if h == nil {
fmt.Println("nil")
} else {
fmt.Println("not nil")
}
}答:B
解析:
这道题里面,是将 hello() 赋值给变量h,而不是函数的返回值,所以输出 not nil
func GetValue() int {
return 1
}
func main() {
i := GetValue()
switch i.(type) {
case int:
fmt.Println("int")
case string:
fmt.Println("string")
case interface{}:
fmt.Println("interface")
default:
fmt.Println("unknown")
}
}答:编译失败
解析:
只有接口类型才能使用类型选择 类型选择的语法形如:i.(type),其中i是接口,type是固定关键字,需要注意的是,只有接口类型才可以使用类型选择。
答:A、B、C
解析:
A、B都是申明channel;C读取channel;写channel是必须带上值,所以D错误。
type person struct {
name string
}
func main() {
var m map[person]int
p := person{"make"}
fmt.Println(m[p])
}答:A
解析:
打印一个map中不存在的值时,返回元素类型的零值。这个例子中,m的类型是map[person]int,因为m中 不存在p,所以打印int类型的零值,即0。
func hello(num ...int) {
num[0] = 18
}
func main() {
i := []int{5, 6, 7}
hello(i..No open issues yet, or sync has not completed.