博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
Go面试:面试题笔记整理(一)
阅读量:3594 次
发布时间:2019-05-20

本文共 11335 字,大约阅读时间需要 37 分钟。

 对里面的部分题目做一些笔记备查。


33. 【中级】 golang中的引用类型包括()

A. 数组切片
B. map
C. channel
D. interface
参考答案:ABCD
这道题已经过时了,在2013年4月3日的github提交中已经明确说了。而slice源码的说明也由“引用”改成了“描述符”。Go只有值传递,没有所谓的引用传递。上题应该改为哪些类型包含有指针。


34. 【中级】 golang中的指针运算包括()

A. 可以对指针进行自增或自减运算
B. 可以通过“&”取指针的地址
C. 可以通过“*”取指针指向的数据
D. 可以对指针进行下标运算
参考答案:BC

D选项应该也是对的,在Go13.8里指向数组的指针的下标运算是可以支持的:

package main import "fmt" func main() {	var a = [3]int{998, 999, 1000}	var ip *[3]int = &a 	for i := 0; i < len(a); i++ {		fmt.Printf("ip[%d]=%d\n", i, ip[i])	}}

输出:

ip[0]=998ip[1]=999ip[2]=1000

 


36. 【中级】下面赋值正确的是()

A. var x = nil
B. var x interface{} = nil
C. var x string = nil
D. var x error = nil
参考答案:BD

可以赋值成nil的变量类型有7种:1)任意类型的指针变量,2)函数变量,3)接口,4)error,5)map, 6)切片 7)通道。这些变量默认值就是nil,实际上都不用赋值成nil。

package mainimport "fmt"func main() {	var ptrI *int	var f func()	var iface interface{}	var err error	var m map[string]string	var sl []string	var ch chan int	if ptrI == nil {fmt.Printf("1) pointer is nil\n")}	if f == nil {fmt.Printf("2) func is nil\n")}	if iface == nil {fmt.Printf("3) interface is nil\n")}	if err == nil {fmt.Printf("4) error is nil\n")}	if m == nil {fmt.Printf("5) map is nil\n")}	if sl == nil {fmt.Printf("6) slice is nil\n")}	if ch == nil {fmt.Printf("7) ch is nil\n")}}

输出: 

1) pointer is nil2) func is nil3) interface is nil4) error is nil5) map is nil6) slice is nil7) ch is nil

 不能赋值成nil的变量类型,会在编译时报错:

package mainimport "fmt"type Person struct {	name string}func main() {	var str string = nil	var person Person = nil	var i int = nil	var b bool = nil	var x = nil	fmt.Printf("str=%v person=%v i=%v b=%v x=%v", str, person, i, b, x)}

 编译报错:

# command-line-arguments./tryinit.go:10:6: cannot use nil as type string in assignment./tryinit.go:11:6: cannot use nil as type Person in assignment./tryinit.go:12:6: cannot use nil as type int in assignment./tryinit.go:13:6: use of untyped nil

38. 【中级】从切片中删除一个元素,下面的算法实现正确的是()

A.
func (s *Slice)Remove(value interface{})error {
    for i, v := range *s {
       if isEqual(value, v) {
           if i== len(*s) - 1 {
               *s = (*s)[:i]
           }else {
               *s = append((*s)[:i],(*s)[i + 2:]...)
           }
           return nil
       }
    }
    return ERR_ELEM_NT_EXIST
}

B.

func (s*Slice)Remove(value interface{}) error {
    for i, v:= range *s {
        if isEqual(value, v) {
            *s =append((*s)[:i],(*s)[i + 1:])
            return nil
        }
    }
    returnERR_ELEM_NT_EXIST
}

C.

func (s*Slice)Remove(value interface{}) error {
     for i, v:= range *s {
         if isEqual(value, v) {
             delete(*s, v)
             return nil
         }
     }
     returnERR_ELEM_NT_EXIST
}

D.

func (s*Slice)Remove(value interface{}) error {
    for i, v:= range *s {
        if isEqual(value, v) {
            *s =append((*s)[:i],(*s)[i + 1:]...)
            return nil
        }
    }
    returnERR_ELEM_NT_EXIST
}

参考答案:D

A,切片截取是前闭后开;B,append追加另一个切片时需要加"...";C,delete是map的删除方式


51. 【初级】对于局部变量整型切片x的赋值,下面定义正确的是()

A. x := []int{

                 1, 2, 3,
                 4, 5, 6,
                 }
B. x :=[]int{
           1, 2, 3,
           4, 5, 6
          }
C. x :=[]int{
                1, 2, 3,
                4, 5, 6}
D. x :=[]int{1, 2, 3, 4, 5, 6,}

参考答案:ACD

切片赋值时,最后一个元素后面如果有逗号则“}”可以换行或者不换行,否则”}“必须和最后一个元素保持在同一行。


55. 【初级】关于变量的自增和自减操作,下面语句正确的是()

A. i := 1;i++

B. i := 1;j = i++
C. i := 1;++i
D. i := 1;i--

参考答案:AD

Go目前只支持后置自增自减运算符,而且不能用于赋值或者作为参数传递给函数。

package mainimport "fmt"func main() {	i:=1;i--	j := i++  //错误	if i++ > 0 { //错误		fmt.Printf("i=%v\n", i++) //错误	}	++i //错误	fmt.Printf("i=%v j=%v\n", i, j)}

编译报错:

# command-line-arguments./example.go:7:8: syntax error: unexpected ++ at end of statement./example.go:8:9: syntax error: unexpected >, expecting {./example.go:9:25: syntax error: unexpected ++, expecting comma or )./example.go:11:2: syntax error: unexpected ++, expecting }

57. 【中级】关于函数声明,下面语法错误的是()

A. func f(a, b int) (value int, err error)
B. func f(a int, b int) (value int, err error)
C. func f(a, b int) (value int, error)
D. func f(a int, b int) (int, int, error)

参考答案:C

Go语言的函数返回值,要么全是非命名的返回值,要么全是命名的返回值,不能即有非命名的又有命名的返回值,否则编译会报错:

syntax error: mixed named and unnamed function parameters

58. 【中级】如果Add函数的调用代码为:

func main() {

var a Integer = 1
var b Integer = 2
var i interface{} = &a
sum := i.(*Integer).Add(b)
fmt.Println(sum)
}
则Add函数定义正确的是()
A.
type Integer int
func (a Integer) Add(b Integer) Integer {
 return a + b
}
B
type Integer int
func (a Integer) Add(b *Integer) Integer {
 return a + *b
}
C
type Integer int
func (a *Integer) Add(b Integer) Integer {
 return *a + b
}
D
type Integer int
func (a *Integer) Add(b *Integer) Integer {
 return *a + *b
}
参考答案:AC
对于方法的参数而言,指针类型的参数不能接受值类型的参数,反之亦然,所以BD是错的。而对于结构体的方法而言,不论定义成值方法或者指针方法,都可以同时支持用指针或者非指针实例来调用。(可能是在编译期完成的转换,后续还需要确认)有两种特殊情况只能定义成值方法:

一是接口断言成非指针实例,例如把main函数改为:

func main() {	var a Integer = 1	var b Integer = 2	var c interface{} = a	sum := c.(Integer).Add(b)	fmt.Println(sum)}

则答案是 A

运行C则编译报错:

./example.go:9:20: cannot call pointer method on c.(Integer)./example.go:9:20: cannot take the address of c.(Integer)

二是类型强制转换,例如把main函数改为:

func main() {	var a int = 1	var b Integer = 2	sum := Integer(a).Add(b)	fmt.Println(sum)}

则答案是 A

运行C则同样是编译报错:

./example.go:8:19: cannot call pointer method on Integer(a)./example.go:8:19: cannot take the address of Integer(a)

72. 【中级】关于GetPodAction定义,下面赋值正确的是()

type Fragment interface {
    Exec(transInfo *TransInfo) error
}
type GetPodAction struct {
}
func (g GetPodAction) Exec(transInfo *TransInfo) error {
    return nil
}
A. var fragment Fragment =new(GetPodAction)
B. var fragment Fragment = GetPodAction
C. var fragment Fragment = &GetPodAction{}
D. var fragment Fragment = GetPodAction{}
参考答案:ACD
Fragment是接口所以赋值成指针或者非指针,AC是指针,D是非指针。B编译报错“type GetPodAction is not an expression”
结构体创建实例有两种等价的形式:
1) var g GetPodAction; 2) g :=  GetPodAction{}


82. 【中级】关于接口,下面说法正确的是()

A. 只要两个接口拥有相同的方法列表(次序不同不要紧),那么它们就是等价的,可以相互赋值
B. 如果接口A的方法列表是接口B的方法列表的子集,那么接口B可以赋值给接口A
C. 接口查询是否成功,要在运行期才能够确定
D. 接口赋值是否可行,要在运行期才能够确定

参考答案:ABC

接口赋值时编译期就可以报错。
验证代码:

package mainimport "fmt"type A interface {	f1()	f2()	f3()}type B interface {	f2()	f1()}type AImpl struct {}func (a AImpl) f1() {	fmt.Printf("call AImpl f1()\n")}func (a AImpl) f2() {	fmt.Printf("call AImpl f2()\n")}func (a AImpl) f3() {	fmt.Printf("call AImpl f3()\n")}func main() {	var a A = AImpl{}	var b B = a	b.f1()	//接口查询,判断b是否实现了接口A	if c, ok := b.(A); ok {		c.f3()	}}

输出:

call AImpl f1()call AImpl f3()

83. 【初级】关于channel,下面语法正确的是()

A. var ch chan int
B. ch := make(chan int)
C. <- ch
D. ch <-
参考答案:ABC


85. 【中级】 golang中大多数数据类型都可以转化为有效的JSON文本,下面几种类型除外()

A. 指针
B. channel
C. complex
D. 函数
参考答案:BCD


87. 【初级】 flag是bool型变量,下面if表达式符合编码规范的是()

A. if flag == 1
B. if flag
C. if flag == false
D. if !flag
参考答案:BD
这道题C也是符合规范的,Go的源代码有很多这样的写法,例如:runtime/pprof/internal/profile:

func encodeBoolOpt(b *buffer, tag int, x bool) {	if x == false {		return	}	encodeBool(b, tag, x)}

88. 【初级】 value是整型变量,下面if表达式符合编码规范的是()

A. if value == 0
B. if value
C. if value != 0
D. if !value
参考答案:AC
BD两项只能是bool变量,否则编译报错:“non-bool value (type int) used as if condition”,“invalid operation: ! int”


91. 【中级】关于slice或map操作,下面正确的是()

A.
var s []int
s = append(s,1)
B.
var m map[string]int
m["one"] = 1
C.
var s []int
s = make([]int, 0)
s = append(s,1)

D.

var m map[string]int
m = make(map[string]int)
m["one"] = 1

参考答案:ACD

slice和map在插入数据之前都需要分配内存,而函数内置有内存分配操作,所以在调用append之前可以不用make切片。
 


93. 【中级】关于channel的特性,下面说法正确的是()

A. 给一个 nil channel 发送数据,造成永远阻塞
B. 从一个 nil channel 接收数据,造成永远阻塞
C. 给一个已经关闭的 channel 发送数据,引起 panic
D. 从一个已经关闭的 channel 接收数据,如果缓冲区中为空,则返回一个零值

参考答案:ABCD

这道题AB两个选项应该是适用于Go的早期版本,在Go1.13.8里面,AB直接报fatal error然后退出。C,D是正确的。
下面是一段能正常运行的代码:

func main() {	ch := make(chan bool)	go func(ch chan bool) {		time.Sleep(1 * time.Second)		b := <-ch		fmt.Printf("b=%v\n", b)	}(ch)	ch <- true	fmt.Printf("exit\n")}
b=trueexit

按照AB说法,把"ch := make(chan bool)"改成:

func main() {	var ch chan bool	go func(ch chan bool) {		time.Sleep(1 * time.Second)		b := <-ch		fmt.Printf("b=%v\n", b)	}(ch)	ch <- true	fmt.Printf("exit\n")}

报错退出:

fatal error: all goroutines are asleep - deadlock!goroutine 1 [chan send (nil chan)]:main.main()        /home/zhoupeng/go-test/src/tutorial/example.go:15 +0x5bgoroutine 6 [chan receive (nil chan)]:main.main.func1(0x0)        /home/zhoupeng/go-test/src/tutorial/example.go:12 +0x4bcreated by main.main        /home/zhoupeng/go-test/src/tutorial/example.go:10 +0x42exit status 2

验证C,在“ch <- true”之前加入“close(ch)”,则报错:“panic: send on closed channel”

func main() {	ch := make(chan bool)	go func(ch chan bool) {		time.Sleep(1 * time.Second)		b := <-ch		fmt.Printf("b=%v\n", b)	}(ch)	close(ch)	ch <- true	fmt.Printf("exit\n")}

验证D,通道写入true之后关闭通道,等待3秒,协程等待1秒后连读2次通道,第一次读到缓冲区里的“true”,第二次缓冲区为空则读取到布尔变量的零值false。注,数值型变量的零值是0,字符串的零值是“”。

func main() {	ch := make(chan bool, 1)	go func(ch chan bool) {		time.Sleep(1 * time.Second)		b1 := <-ch		fmt.Printf("b1=%v\n", b1)		b2 := <-ch		fmt.Printf("b2=%v\n", b2)	}(ch)	ch <- true	close(ch)	time.Sleep(3 * time.Second)	fmt.Printf("exit\n")}
b1=trueb2=falseexit

94. 【中级】关于无缓冲和有冲突的channel,下面说法正确的是()

A. 无缓冲的channel是默认的缓冲为1的channel
B. 无缓冲的channel和有缓冲的channel都是同步的
C. 无缓冲的channel和有缓冲的channel都是非同步的
D. 无缓冲的channel是同步的,而有缓冲的channel是非同步的

参考答案:D

无缓冲的channel是默认的缓冲为0的channel,对应代码如“make(chan int, 0)”,0是默认值可以省略。有缓冲的channel是非同步的指的是发送/接收操作只在缓冲区满了才阻塞,否则继续执行后面的代码。
缓存为1的时序验证:

func main() {	ch := make(chan int, 1)	go func(ch chan int) {		time.Sleep(2 * time.Second)		i1 := <-ch		log.Printf("i1=%v\n", i1)		time.Sleep(2 * time.Second)		i2 := <-ch		log.Printf("i2=%v\n", i2)	}(ch)	log.Printf("send 1\n")	ch <- 1	log.Printf("send 2\n")	ch <- 2	log.Printf("main sleep\n")	time.Sleep(3 * time.Second)	log.Printf("exit\n")}
2020/07/13 14:19:26 send 12020/07/13 14:19:26 send 22020/07/13 14:19:28 i1=12020/07/13 14:19:28 main sleep2020/07/13 14:19:30 i2=22020/07/13 14:19:31 exit

从输出可以看出,缓冲区是一个先进先出的队列,发送的顺序是1,2,接收的顺序也是1,2。运行到send2时缓冲区已满,main函数所在协程阻塞,2秒之后另一个协程从通道读取到第一个值1,缓冲区不再是已满的状态,main函数停止阻塞继续执行后面的代码打印“main sleep”,再过2秒之后另一个协程从通道读取到第二个值2。

如果把上述代码改为非缓冲通道,则输出时序为:

2020/07/13 14:37:15 send 12020/07/13 14:37:17 i1=12020/07/13 14:37:17 send 22020/07/13 14:37:19 i2=22020/07/13 14:37:19 main sleep2020/07/13 14:37:22 exit

send1之后就会阻塞,2秒之后等另一个协程读取到第一个值1之后,main再发送send 2,发了之后再阻塞 ,2秒之后等另一个协程读取到第二个值2之后,main解除阻塞。


95. 【中级】关于异常的触发,下面说法正确的是()

A. 空指针解析
B. 下标越界
C. 除数为0
D. 调用panic函数
参考答案:ABCD


96. 【中级】关于cap函数的适用类型,下面说法正确的是()

A. array
B. slice
C. map
D. channel
参考答案:ABD

func main(){	var a [3]int	var sl = make([]int, 1, 5)	var m = make(map[int]int, 100)	var ch = make(chan int, 10)	log.Printf("%d\n",cap(a))	log.Printf("%d\n",cap(sl))	log.Printf("%d\n",cap(m))	log.Printf("%d\n",cap(ch))}

编译报错:

invalid argument m (type map[int]int) for cap

 


100.             【中级】关于map,下面说法正确的是()

A. map反序列化时json.unmarshal的入参必须为map的地址
B. 在函数调用中传递map,则子函数中对map元素的增加不会导致父函数中map的修改
C. 在函数调用中传递map,则子函数中对map元素的修改不会导致父函数中map的修改
D. 不能使用内置函数delete删除map的元素

参考答案:A

A:func Unmarshal(data [], v interface{})  其中“If v is nil or not a pointer, Unmarshal returns an InvalidUnmarshalError.”所以v只能是非空指针。
B,C:子函数对map的"增,删,改"都会导致父函数中map的改变,验证代码如下:

func test(mp map[int]int){	mp[23] = 321	mp[11] = 100	delete(mp, 12)}func main(){	var m = make(map[int]int)	m[11] = 108	m[12] = 110	log.Printf("%v\n",m)	test(m)	log.Printf("%v\n",m)}
[root@dev tutorial]# go run example.go2020/07/14 10:18:49 map[11:108 12:110]2020/07/14 10:18:49 map[11:100 23:321]

102. 【初级】关于select机制,下面说法正确的是()

A. select机制用来处理异步IO问题
B. select机制最大的一条限制就是每个case语句里必须是一个IO操作
C. golang在语言级别支持select关键字
D. select关键字的用法与switch语句非常类似,后面要带判断条件

参考答案:ABC

A 不准确,可以用来处理异步IO问题,也可以处理同步IO; B不对,每个case语句里必须是接收通道的操作,不一定非得是IO操作,golang并没有这样的硬性限制。C. 是对的,golang ”语言级别“ 支持select关键字,而不需要引用其它包。D.后面跟的是对通道的接收操作。


103.             【初级】关于内存泄露,下面说法正确的是()

A. golang有自动垃圾回收,不存在内存泄露
B. golang中检测内存泄露主要依靠的是pprof包
C. 内存泄露可以在编译阶段发现
D. 应定期使用浏览器来查看系统的实时内存信息,及时发现内存泄露问题

参考答案:BD

转载地址:http://lnmwn.baihongyu.com/

你可能感兴趣的文章
vue+ckplayer+rtmp
查看>>
vue+pg库+openlayer5+geoserver+离线地图瓦片构建gis地图+地图撒点+点击点出现地图弹框(***完整流程***)
查看>>
openlayer5实现地图撒点,点击弹框效果
查看>>
vscode炫酷写代码插件Power Mode
查看>>
实现字符串倒叙
查看>>
node中引入其他ejs文件,并给引入文件传参,类似iframe
查看>>
ejs中在页面上使用if-else
查看>>
moment中时间为12小时制,dayjs中时间为12小时制
查看>>
vue解决打包后文件过大的问题-使用压缩插件打包后压缩文件-compression-webpack-plugin
查看>>
爆料称字节跳动实习生删库
查看>>
无缝滚动lunbot
查看>>
如何将Map集合写入txt文件中
查看>>
springboot参数检验,Assert使用
查看>>
htonl函数原理
查看>>
MACOS的Python虚拟环境使用笔记
查看>>
MAC系统使用Matplotlib显示中文问题亲测有效
查看>>
JavaScript的类型转换笔记
查看>>
JavaScript闭包实现计数器
查看>>
JavaScript中this关键字
查看>>
JavaScript两种定时器的使用
查看>>