91-120

91. 下面代码输出什么?

func main() {
    x := []string{"a", "b", "c"}
    for v := range x {
        fmt.Print(v)
    }
}

答:012

解析:

注意区别下面代码段:

func main() {
    x := []string{"a", "b", "c"}
    for _, v := range x {
        fmt.Print(v)     //输出 abc
    }
}

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

type User struct{}
type User1 User
type User2 = User

func (i User) m1() {
    fmt.Println("m1")
}
func (i User) m2() {
    fmt.Println("m2")
}

func main() {
    var i1 User1
    var i2 User2
    i1.m1()
    i2.m2()
}

答:不能,报错i1.m1 undefined (type User1 has no field or method m1)

解析:

第 2 行代码基于类型 User 创建了新类型 User1,第 3 行代码是创建了 User 的类型别名 User2,注意使用 = 定义类型别名。因为 User2 是别名,完全等价于 User,所以 User2 具有 User 所有的方法。但是 i1.m1() 是不能执行的,因为 User1 没有定义该方法。

93. 关于无缓冲和有冲突的channel,下面说法正确的是?

  • A. 无缓冲的channel是默认的缓冲为1的channel;

  • B. 无缓冲的channel和有缓冲的channel都是同步的;

  • C. 无缓冲的channel和有缓冲的channel都是非同步的;

  • D. 无缓冲的channel是同步的,而有缓冲的channel是非同步的;

答:D

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

答:non-empty interface

解析:

考点:interface 的内部结构,我们知道接口除了有静态类型,还有动态类型和动态值,当且仅当动态值和动态类型都为 nil 时,接口类型值才为 nil。这里的 x 的动态类型是 *int,所以 x 不为 nil。

95. 下面代码输出什么?

答:程序抛异常

解析:

先定义下,第一个协程为 A 协程,第二个协程为 B 协程;当 A 协程还没起时,主协程已经将 channel 关闭了,当 A 协程往关闭的 channel 发送数据时会 panic,panic: send on closed channel

96. 关于select机制,下面说法正确的是?

  • A. select机制用来处理异步IO问题;

  • B. select机制最大的一条限制就是每个case语句里必须是一个IO操作;

  • C. golang在语言级别支持select关键字;

  • D. select关键字的用法与switch语句非常类似,后面要带判断条件;

答:A B C

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

答:有方向的 channel 不可以被关闭。

98. 下面这段代码存在什么问题?

答:存在两个问题

解析:

  1. map 需要初始化才能使用;

  2. 指针不支持索引。修复代码如下:

99. 下面代码编译能通过吗?

答:编译错误

解析:

Go 语言中,大括号不能放在单独的一行。

正确的代码如下:

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

答:[1 0 2 3]

解析:

字面量初始化切片时候,可以指定索引,没有指定索引的元素会在前一个索引基础之上加一,所以输出[1 0 2 3],而不是[1 3 2]

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

答:2

解析:

知识点:指针。

p 是指针变量,指向变量 v,*p++操作的意思是取出变量 v 的值并执行加一操作,所以 v 的最终值是 2。

102. 请指出下面代码的错误?

答:变量 one、two 和 three 声明未使用

解析:

知识点:未使用变量

如果有未使用的变量代码将编译失败。但也有例外,函数中声明的变量必须要使用,但可以有未使用的全局变量。函数的参数未使用也是可以的。

如果你给未使用的变量分配了一个新值,代码也还是会编译失败。你需要在某个地方使用这个变量,才能让编译器愉快的编译。

修复代码:

另一个选择是注释掉或者移除未使用的变量 。

103. 下面代码输出什么?

答:运行时错误

解析:

如果类型实现 String() 方法,当格式化输出时会自动使用 String() 方法。上面这段代码是在该类型的 String() 方法内使用格式化输出,导致递归调用,最后抛错。

104. 下面代码输出什么?

答:[1 2 3 4 5]

解析:

a 在 for range 过程中增加了两个元素,len 由 5 增加到 7,但 for range 时会使用 a 的副本 a' 参与循环,副本的 len 依旧是 5,因此 for range 只会循环 5 次,也就只获取 a 对应的底层数组的前 5 个元素。

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

答:导入的包没有被使用

解析:

如果引入一个包,但是未使用其中如何函数、接口、结构体或变量的话,代码将编译失败。

如果你真的需要引入包,可以使用下划线操作符,_,来作为这个包的名字,从而避免失败。下划线操作符用于引入,但不使用。

我们还可以注释或者移除未使用的包。

修复代码:

106. 下面代码输出什么?

  • A. true true true

  • B. false true true

  • C. true true true

  • D. false true false

答:D

解析:

知识点:类型断言。

类型断言语法:i.(Type),其中 i 是接口,Type 是类型或接口。编译时会自动检测 i 的动态类型与 Type 是否一致。但是,如果动态类型不存在,则断言总是失败。

107. 下面代码有几处错误的地方?请说明原因。

答:有 1 处错误

解析:

有 1 处错误,不能对 nil 的 map 直接赋值,需要使用 make() 初始化。但可以使用 append() 函数对为 nil 的 slice 增加元素。

修复代码:

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

答:使用 cap() 获取 map 的容量

解析:

  1. 使用 make 创建 map 变量时可以指定第二个参数,不过会被忽略。

  2. cap() 函数适用于数组、数组指针、slice 和 channel,不适用于 map,可以使用 len() 返回 map 的元素个数。

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

解析:

nil 用于表示 interface、函数、maps、slices 和 channels 的“零值”。如果不指定变量的类型,编译器猜不出变量的具体类型,导致编译错误。

修复代码:

110. 下面代码能编译通过吗?

答:编译失败

解析:

不能使用短变量声明设置结构体字段值,修复代码:

111. 下面代码有什么错误?

答:变量重复声明

解析:

不能在单独的声明中重复声明一个变量,但在多变量声明的时候是可以的,但必须保证至少有一个变量是新声明的。

修复代码:

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

答:编译错误

解析:

第四行代码没有逗号。用字面量初始化数组、slice 和 map 时,最好是在每个元素后面加上逗号,即使是声明在一行或者多行都不会出错。

修复代码:

113. 下面代码输出什么?

答:34

解析:

与 rune 是 int32 的别名一样,byte 是 uint8 的别名,别名类型无序转换,可直接转换。

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

答:编译可以通过

解析:

知识点:常量。

常量是一个简单值的标识符,在程序运行时,不会被修改的量。不像变量,常量未使用是能编译通过的。

115. 下面代码输出什么?

答:

解析:

常量组中如不指定类型和初始化值,则与上一行非空常量右值相同

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

答:将 nil 分配给 string 类型的变量

解析:

修复代码:

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

解析:

对于自增、自减,需要注意:

  • 自增、自减不在是运算符,只能作为独立语句,而不是表达式;

  • 不像其他语言,Go 语言中不支持 ++i 和 --i 操作;

表达式通常是求值代码,可作为右值或参数使用。而语句表示完成一个任务,比如 if、for 语句等。表达式可作为语句使用,但语句不能当做表达式。

修复代码:

118. 下面代码最后一行输出什么?请说明原因。

答:输出1

解析:

知识点:变量隐藏。

使用变量简短声明符号 := 时,如果符号左边有多个变量,只需要保证至少有一个变量是新声明的,并对已定义的变量尽进行赋值操作。但如果出现作用域之后,就会导致变量隐藏的问题,就像这个例子一样。

这个坑很容易挖,但又很难发现。即使对于经验丰富的 Go 开发者而言,这也是一个非常常见的陷阱。

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

答:编译错误

解析:

:= 操作符不能用于结构体字段赋值。

120. 下面的代码输出什么?

答:编译错误

解析:

很多语言都是采用 ~ 作为按位取反运算符,Go 里面采用的是^ 。按位取反之后返回一个每个 bit 位都取反的数,对于有符号的整数来说,是按照补码进行取反操作的(快速计算方法:对数 a 取反,结果为 -(a+1) ),对于无符号整数来说就是按位取反。例如:

另外需要注意的是,如果作为二元运算符,^ 表示按位异或,即:对应位相同为 0,相异为 1。例如:

给大家重点介绍下这个操作符 &^,按位置零,例如:z = x &^ y,表示如果 y 中的 bit 位为 1,则 z 对应 bit 位为 0,否则 z 对应 bit 位等于 x 中相应的 bit 位的值。

不知道大家发现没有,我们还可以这样理解或操作符 | ,表达式 z = x | y,如果 y 中的 bit 位为 1,则 z 对应 bit 位为 1,否则 z 对应 bit 位等于 x 中相应的 bit 位的值,与 &^ 完全相反。

输出:

最后更新于