61-90

61. 下面这段代码输出什么?

const (
    a = iota
    b = iota
)
const (
    name = "name"
    c    = iota
    d    = iota
)
func main() {
    fmt.Println(a)
    fmt.Println(b)
    fmt.Println(c)
    fmt.Println(d)
}

答:0 1 1 2

解析:

知识点:iota 的用法。

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

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

62. 下面这段代码输出什么?为什么?

答:s is nilp is not nil

解析:

这道题会不会有点诧异,我们分配给变量 p 的值明明是 nil,然而 p 却不是 nil。记住一点,当且仅当动态值和动态类型都为 nil 时,接口类型值才为 nil。上面的代码,给变量 p 赋值之后,p 的动态值是 nil,但是动态类型却是 *Student,是一个 nil 指针,所以相等条件不成立。

63. 下面这段代码输出什么?

答:South

解析:

知识点:iota 的用法、类型的 String() 方法。

64. 下面代码输出什么?

  • A. 4

  • B. compilation error

答:B

解析:

编译报错 cannot assign to struct field m["foo"].x in map。错误原因:对于类似 X = Y的赋值操作,必须知道 X 的地址,才能够将 Y 的值赋给 X,但 go 中的 map 的 value 本身是不可寻址的。

有两个解决办法:

  1. 使用临时变量

  2. 修改数据结构

65. 下面的代码有什么问题?

答:有两处错误

解析:

  • go 中不同类型是不能比较的,而数组长度是数组类型的一部分,所以 […]int{1}[2]int{1} 是两种不同的类型,不能比较;

  • 切片是不能比较的;

66. 下面这段代码输出什么?如果编译错误的话,为什么?

  • A. 5 5

  • B. runtime error

答:B

解析:

知识点:变量作用域。

问题出在操作符:=,对于使用:=定义的变量,如果新变量与同名已定义的变量不在同一个作用域中,那么 Go 会新定义这个变量。对于本例来说,main() 函数里的 p 是新定义的变量,会遮住全局变量 p,导致执行到bar()时程序,全局变量 p 依然还是 nil,程序随即 Crash。

正确的做法是将 main() 函数修改为:

67. 下面这段代码能否正常结束?

答:不会出现死循环,能正常结束

解析:

循环次数在循环开始前就已经确定,循环内改变切片的长度,不影响循环次数。

68. 下面这段代码输出什么?为什么?

答:

解析:

for range 使用短变量声明(:=)的形式迭代变量,需要注意的是,变量 i、v 在每次循环体中都会被重用,而不是重新声明。

各个 goroutine 中输出的 i、v 值都是 for range 循环结束后的 i、v 最终值,而不是各个goroutine启动时的i, v值。可以理解为闭包引用,使用的是上下文环境的值。

两种可行的 fix 方法:

  1. 使用函数传递

  2. 使用临时变量保留当前值

69. 下面这段代码输出什么?

答:7

解析:

第一步执行r = n +1,接着执行第二个 defer,由于此时 f() 未定义,引发异常,随即执行第一个 defer,异常被 recover(),程序正常执行,最后 return。

70. 下面这段代码输出什么?

答:

解析:

range 表达式是副本参与循环,就是说例子中参与循环的是 a 的副本,而不是真正的 a。就这个例子来说,假设 b 是 a 的副本,则 range 循环代码是这样的:

因此无论 a 被如何修改,其副本 b 依旧保持原值,并且参与循环的是 b,因此 v 从 b 中取出的仍旧是 a 的原值,而非修改后的值。

如果想要 r 和 a 一样输出,修复办法:

输出:

修复代码中,使用 *[5]int 作为 range 表达式,其副本依旧是一个指向原数组 a 的指针,因此后续所有循环中均是 &a 指向的原数组亲自参与的,因此 v 能从 &a 指向的原数组中取出 a 修改后的值。

71. 下面这段代码输出什么?

答:

解析:

知识点:可变函数、append()操作。

Go 提供的语法糖...,可以将 slice 传进可变函数,不会创建新的切片。第一次调用 change() 时,append() 操作使切片底层数组发生了扩容,原 slice 的底层数组不会改变;第二次调用change() 函数时,使用了操作符[i,j]获得一个新的切片,假定为 slice1,它的底层数组和原切片底层数组是重合的,不过 slice1 的长度、容量分别是 2、5,所以在 change() 函数中对 slice1 底层数组的修改会影响到原切片。

golang

72. 下面这段代码输出什么?

答:

解析:

切片在 go 的内部结构有一个指向底层数组的指针,当 range 表达式发生复制时,副本的指针依旧指向原底层数组,所以对切片的修改都会反应到底层数组上,所以通过 v 可以获得修改后的数组元素。

73. 下面这段代码输出结果正确正确吗?

答:s2 的输出结果错误

解析:

s2 的输出是 &{C} &{C} &{C},for range 使用短变量声明(:=)的形式迭代变量时,变量 i、value 在每次循环体中都会被重用,而不是重新声明。所以 s2 每次填充的都是临时变量 value 的地址,而在最后一次循环中,value 被赋值为{c}。因此,s2 输出的时候显示出了三个 &{c}。

可行的解决办法如下:

74. 下面代码里的 counter 的输出值?

  • A. 2

  • B. 3

  • C. 2 或 3

答:C

解析:

for range map 是无序的,如果第一次循环到 A,则输出 3;否则输出 2。

75. 关于协程,下面说法正确是()

  • A. 协程和线程都可以实现程序的并发执行;

  • B. 线程比协程更轻量级;

  • C. 协程不存在死锁问题;

  • D. 通过 channel 来进行协程间的通信;

答:A D

76. 关于循环语句,下面说法正确的有()

  • A. 循环语句既支持 for 关键字,也支持 while 和 do-while;

  • B. 关键字 for 的基本使用方法与 C/C++ 中没有任何差异;

  • C. for 循环支持 continue 和 break 来控制循环,但是它提供了一个更高级的 break,可以选择中断哪一个循环;

  • D. for 循环不支持以逗号为间隔的多个赋值语句,必须使用平行赋值的方式来初始化多个变量;

答:C D

77. 下面代码输出正确的是?

  • A. s: [Z,B,C]

  • B. s: [A,Z,C]

答:A

解析:

知识点:多重赋值。

多重赋值分为两个步骤,有先后顺序:

  • 计算等号左边的索引表达式和取址表达式,接着计算等号右边的表达式;

  • 赋值;

所以本例,会先计算 s[i-1],等号右边是两个表达式是常量,所以赋值运算等同于 i, s[0] = 2, "Z"

78. 关于类型转化,下面选项正确的是?

答:C

解析:

知识点:强制类型转化

79. 关于switch语句,下面说法正确的有?

  • A. 条件表达式必须为常量或者整数;

  • B. 单个case中,可以出现多个结果选项;

  • C. 需要用break来明确退出一个case;

  • D. 只有在case中明确添加fallthrough关键字,才会继续执行紧跟的下一个case;

答:B D

80. 如果 Add() 函数的调用代码为:

则Add函数定义正确的是()

答:A C

解析:

知识点:类型断言、方法集。

81. 关于 bool 变量 b 的赋值,下面错误的用法是?

  • A. b = true

  • B. b = 1

  • C. b = bool(1)

  • D. b = (1 == 2)

答:B C

82. 关于变量的自增和自减操作,下面语句正确的是?

答:A D

解析:

知识点:自增自减操作。

i++ 和 i-- 在 Go 语言中是语句,不是表达式,因此不能赋值给另外的变量。此外没有 ++i 和 --i。

83. 关于GetPodAction定义,下面赋值正确的是

  • A. var fragment Fragment = new(GetPodAction)

  • B. var fragment Fragment = GetPodAction

  • C. var fragment Fragment = &GetPodAction{}

  • D. var fragment Fragment = GetPodAction{}

答:A C D

84. 关于函数声明,下面语法正确的是?

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

答:A B D

85. 关于整型切片的初始化,下面正确的是?

  • A. s := make([]int)

  • B. s := make([]int, 0)

  • C. s := make([]int, 5, 10)

  • D. s := []int{1, 2, 3, 4, 5}

答:B C D

86. 下面代码会触发异常吗?请说明。

解析:

select 会随机选择一个可用通道做收发操作,所以可能触发异常,也可能不会。

87. 关于channel的特性,下面说法正确的是?

  • A. 给一个 nil channel 发送数据,造成永远阻塞

  • B. 从一个 nil channel 接收数据,造成永远阻塞

  • C. 给一个已经关闭的 channel 发送数据,引起 panic

  • D. 从一个已经关闭的 channel 接收数据,如果缓冲区中为空,则返回一个零值

答:A B C D

88. 下面代码有什么问题?

答:编译报错

解析:

编译报错cannot take the address of i。知识点:常量。常量不同于变量的在运行期分配内存,常量通常会被编译器在预处理阶段直接展开,作为指令数据使用,所以常量无法寻址。

89. 下面代码能否编译通过?如果通过,输出什么?

答:不能通过编译

解析:

知识点:函数返回值类型。nil 可以用作 interface、function、pointer、map、slice 和 channel 的“空值”。但是如果不特别指定的话,Go 语言不能识别类型,所以会报错:cannot use nil as type string in return argument

90. 关于异常的触发,下面说法正确的是?

  • A. 空指针解析;

  • B. 下标越界;

  • C. 除数为0;

  • D. 调用panic函数;

答:A B C D

最后更新于