• Go语言基础面试题


    一、选择题
    1.关于异常设计,下面说法正确的是()

    A. 在程序开发阶段,坚持速错,让程序异常崩溃 // 开发--测试--准生产--生产
    B. 在程序部署后,应恢复异常避免程序终止
    C. 一切皆错误,不用进行异常设计
    D. 对于不应该出现的分支,使用异常处理
    
    参考答案:ABD
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6

    2.关于异常的触发,下面说法正确的是()

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

    3.关于函数返回值的错误设计,下面说法正确的是()

    A. 如果失败原因只有一个,则返回bool
    B. 如果失败原因超过一个,则返回error
    C. 如果没有失败原因,则不返回bool或error
    D. 如果重试几次可以避免失败,则不要立即返回bool或error
    
    参考答案:ABCD
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6

    4.下面关于recover使用正确的是?

    A.recover()
    B.defer recover()
    C.defer func() {
    recover()
    }()
    D. defer func() {
    defer func() {
    recover()
    }()
    }()
    
    
    答案:C。recover() 必须在 defer() 函数中直接调用才有效。,不能嵌套使用,不能直接使用
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13

    5.函数执行时,如果由于 panic 导致了异常,则延迟函数不会执行。这一说法是否正确?

    A. 正确
    B. 错误
    参考答案及解析:B。 defer结合recover可以修复panic
    6.错误是业务过程的一部分,而异常不是,这句话是否正确()
    
    A.正确
    
    B.错误
    
    答案:A。异常是要避免的
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10

    二、简答题
    1.写出下面代码的输出

    package main
    
    import "fmt"
    
    func main() {
    defer_all()
    panic("触发异常")
    }
    
    func defer_all() {
    defer func() {
    fmt.Println("打印前")
    }()
    defer func() {
    fmt.Println("打印中")
    }()
    defer func() {
    fmt.Println("打印后")
    }()
    }
    
    这道题主要考察的是对 defer 的理解,defer 主要是延迟函数,延迟到调用者函数执行 return 命令之前
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22

    2.写出下面代码的执行结果

    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
    
    • 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

    3.下面代码的执行结果为?

    package main
    
    import "fmt"
    
    func main() {
    a := 1
    b := 2
    defer Sum( a, b)
    a = 3
    defer Sum( a, b)
    b = 4
    }
    
    func Sum(a, b int) {
    ret := a + b
    fmt.Println(a, b, ret)
    }
    
    
    
    答案:defer先进后出,后进先出
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21

    4.下面代码能正常编译吗?

    package main
    
    import "fmt"
    
    func main() {
    nil := 1
    var map_data map[string]int = nil
    fmt.Println(map_data)
    }
    
    
    答案:不能,此时的nil是int类型的变量
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12

    一、选择题
    1.关于协程,下面说法正确是?

    A. 协程和线程都可以实现程序的并发执行
    B. 线程比协程更轻量级
    C. 协程不存在死锁问题
    D. 通过channel来进行协程间的通信
    
    参考答案:AD
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6

    2.关于channel,下面语法正确的是()

    A. var ch chan int
    B. ch := make(chan int)
    C. <- ch
    D. ch <-
    
    
    
    参考答案:ABC
    
    
    D答案少了写入的数据:ch <- 3
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11

    3.关于同步锁,下面说法正确的是()

    A. 当一个goroutine获得了Mutex后,其他goroutine就只能乖乖的等待,除非该goroutine释放这个Mutex
    B. RWMutex在读锁占用的情况下,会阻止写,但不阻止读
    C. RWMutex在写锁占用情况下,会阻止任何其他goroutine(无论读和写)进来,整个锁相当于由该goroutine独占
    D. Lock()操作需要保证有Unlock()或RUnlock()调用与之对应
    
    参考答案:ABC。Lock对应Unlock,RLock对应RUnlock
    
    读写锁:
    写锁:写写互斥,写读互斥
    读锁:读读不互斥,读写互斥
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10

    4.关于channel的特性,下面说法正确的是()

    A. 给一个 nil channel 发送数据,造成永远阻塞
    B. 从一个 nil channel 接收数据,造成永远阻塞
    C. 给一个已经关闭的 channel 发送数据,引起 panic
    D. 从一个已经关闭的 channel 接收数据,如果缓冲区中为空,则返回一个零值
    
    参考答案:ABCD
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6

    5.关于 channel 下面描述正确的是?

    A. 向已关闭的通道发送数据会引发 panic;
    
    B. 从已关闭的缓冲通道接收数据,返回已缓冲数据或者零值;
    
    C. 无论接收还是发送,nil 通道都会阻塞;
    
    参考答案及解析:ABC。
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7

    6.关于无缓冲和有冲突的channel,下面说法正确的是()

    A. 无缓冲的channel是默认的缓冲为1的channel // 默认位0
    B. 无缓冲的channel和有缓冲的channel都是同步的
    C. 无缓冲的channel和有缓冲的channel都是非同步的
    D. 无缓冲的channel是同步的,而有缓冲的channel是非同步的
    
    参考答案:D。
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6

    7.关于select机制,下面说法正确的是()

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

    8下面代码输出什么?请简要说明。

    type MyMutex struct {
    count int
    sync.Mutex
    }
    
    func main() {
    var mu MyMutex
    mu.Lock()
    var mu1 = mu
    mu.count++
    mu.Unlock()
    mu1.Lock()
    mu1.count++
    mu1.Unlock()
    fmt.Println(mu.count, mu1.count)
    }
    A. 不能编译;
    B. 输出 1, 1;
    C. 输出 1, 2;
    D. fatal error;
    参考答案及解析:D。加锁后复制变量,会将锁的状态也复制,所以 mu1 其实是已经加锁状态,再加锁会死锁。
    
    代码优化后的:
    
    func main() {
    var mu MyMutex
    mu.Lock()
    mu.count++
    mu.Unlock()
    var mu1 = mu
    mu1.Lock()
    mu1.count++
    mu1.Unlock()
    fmt.Println(mu.count, mu1.count)
    }
    
    • 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

    二、简答题
    1.select是随机的还是顺序的?

    随机的
    
    • 1

    2.协程,线程,进程的区别?

    进程是资源的分配和调度的一个独立单元,而线程是CPU调度的基本单元;
    
    同一个进程中可以包括多个线程;
    
    进程结束后它拥有的所有线程都将销毁,而线程的结束不会影响同个进程中的其他线程的结束;
    
    线程共享整个进程的资源(寄存器、堆栈、上下文),一个进程至少包括一个线程;
    
    
    线程中执行时一般都要进行同步和互斥,因为他们共享同一进程的所有资源;
    
    进程是资源分配的单位
    
    线程是操作系统调度的单位
    
    进程切换需要的资源很最大,效率很低 线程切换需要的资源一般,效率一般 协程切换任务资源很小,效率高 多进程、多线程根据cpu核数不一样可能是并行的 也可能是并发的。协程的本质就是使用当前进程在不同的函数代码中切换执行,可以理解为并行。 协程是一个用户层面的概念,不同协程的模型实现可能是单线程,也可能是多线程。
    
    进程拥有自己独立的堆和栈,既不共享堆,亦不共享栈,进程由操作系统调度。(全局变量保存在堆中,局部变量及函数保存在栈中)
    
    线程拥有自己独立的栈和共享的堆,共享堆,不共享栈,线程亦由操作系统调度(标准线程是这样的)。
    
    协程和线程一样共享堆,不共享栈,协程由程序员在协程的代码里显示调度。
    
    一个应用程序一般对应一个进程,一个进程一般有一个主线程,还有若干个辅助线程,线程之间是平行运行的,在线程里面可以开启协程,让程序在特定的时间内运行。
    
    协程和线程的区别是:协程避免了无意义的调度,由此可以提高性能,但也因此,程序员必须自己承担调度的责任,同时,协程也失去了标准线程使用多CPU的能力。
    
    • 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

    3.说说go语言中的协程?

    协程和线程都可以实现程序的并发执行;
    
    通过channel来进行协程间的通信;
    
    只需要在函数调用前添加go关键字即可实现go的协程,创建并发任务;
    
    关键字go并非执行并发任务,而是创建一个并发任务单元;
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7

    4.说说go语言的channel特性?

    给一个 nil channel 发送数据,造成永远阻塞
    
    从一个 nil channel 接收数据,造成永远阻塞
    
    给一个已经关闭的 channel 发送数据,引起 panic
    
    从一个已经关闭的 channel 接收数据,如果缓冲区中为空,则返回一个零值
    
    无缓冲的channel是同步的,而有缓冲的channel是非同步的
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9

    5.说说go语言的select机制?

    A. select机制用来处理异步IO问题
    
    B. select机制最大的一条限制就是每个case语句里必须是一个IO操作
    
    C. golang在语言级别支持select关键字
    
    • 1
    • 2
    • 3
    • 4
    • 5

    6.select可以用于什么?

    常用于gorotine的完美退出
    golang 的 select 就是监听 IO 操作,当 IO 操作发生时,触发相应的动作
    每个case语句里必须是一个IO操作,确切的说,应该是一个面向channel的IO操作
    
    • 1
    • 2
    • 3

    7.主协程如何等其余协程完再操作

    sync.WiteGroup
    
    Add() 指定计数器
    Done() 计数器减1
    Wite() 等待计数器减为0,结束
    
    • 1
    • 2
    • 3
    • 4
    • 5

    8.sync.Once的作用?实现一个单例

    sync.Once 是 Golang package 中使方法只执行一次的对象实现,作用与 init 函数类似。但也有所不同。
    
    init 函数是在文件包首次被加载的时候执行,且只执行一次
    sync.Onc 是在代码运行中需要的时候执行,且只执行一次
    当一个函数不希望程序在一开始的时候就被执行的时候,我们可以使用 sync.Once 。
    
    • 1
    • 2
    • 3
    • 4
    • 5

    9.死锁条件,如何避免?

    死锁产生的原因
    1.系统资源的竞争导致系统资源不足,以及资源分配不当,导致死锁
    2.请求和释放资源的顺序不当,会导致死锁
    如何避免:
    channel推送和读取同时存在时才不会发生死锁,而且需要注意channel读写的顺序,只读或只推都会发生死锁
    
    • 1
    • 2
    • 3
    • 4
    • 5
  • 相关阅读:
    【控制台】报错:Uncaught ReferenceError: process is not defined
    ZZNUOJ_C语言1114:逆序(完整代码)
    数据交换的常见格式,如JSON格式和XML格式
    普林斯顿10分钟剧本创作比赛
    Spring Boot中配置多个数据源
    一个思维狂赚20万+?揭秘电商平台隐藏的流量认知!
    无人机/飞控--ArduPilot、PX4学习记录(4)
    安全算法 - 国密算法
    DataFrame转换为RDD_大数据培训
    Greenplum广播与重分布原理
  • 原文地址:https://blog.csdn.net/ZN175623/article/details/128179679