本篇来点代码问答
常量与变量
- 下列代码的输出是:
1 | func main() { |
- 答案:
golang 100 true
在同一个 const group 中,如果常量定义与前一行的定义一致,则可以省略类型和值。编译时,会按照前一行的定义自动补全。即等价于
1 | func main() { |
- 下列代码的输出是:
1 | func main() { |
- 答案:
编译失败: cannot use M (constant 100 of type int32) as type int in variable declaration
Go 语言中,常量分为无类型常量和有类型常量两种,
const N = 100
,属于无类型常量,赋值给其他变量时,如果字面量能够转换为对应类型的变量,则赋值成功,例如,var x int = N
。但是对于有类型的常量const M int32 = 100
,赋值给其他变量时,需要类型匹配才能成功,所以显示地类型转换:
var y int = int(M)
- 下列代码的输出是:
1 | func main() { |
- 答案:
-128
int8 能表示的数字的范围是
[-2^7, 2^7-1]
,即[-128, 127]
。-128
是无类型常量,转换为int8
,再除以变量-1
,结果为128
,常量除以变量,结果是一个变量。变量转换时允许溢出,符号位变为1,转为补码后恰好等于-128
。
对于有符号整型,最高位是是符号位,计算机用补码表示负数。补码 = 原码取反加一
1 | -1 : 11111111 |
作用域
- 下列代码的输出是:
1 | func main() { |
- 答案:
1 err
:=
表示声明并赋值,=
表示仅赋值。
变量的作用域是大括号,因此在第一个 if 语句if err == nil
内部重新声明且赋值了与外部变量同名的局部变量 err。对该局部变量的赋值不会影响到外部的 err。因此第二个 if 语句if err != nil
不成立。所以只打印了 1 err。
defer 延迟调用
- 下列代码的输出是:
1 | type T struct{} |
- 答案:
132
defer
延迟调用时,需要保存函数指针和参数,因此链式调用的情况下,除了最后一个函数/方法外的函数/方法都会在调用时直接执行。也就是说t.f(1)
直接执行,然后执行fmt.Print(3)
,最后函数返回时再执行.f(2)
,因此输出是132
。
- 下列代码的输出是:
1 | func f(n int) { |
1
打印 1 而不是 101。defer
语句执行时,会将需要延迟调用的函数和参数保存起来,也就是说,执行到defer
时,参数 n(此时等于1) 已经被保存了。因此后面对 n 的改动并不会影响延迟函数调用的结果。
- 下列代码的输出是:
1 | func main() { |
101
匿名函数没有通过传参的方式将 n 传入,因此匿名函数内的 n 和函数外部的 n 是同一个,延迟执行时,已经被改变为 101。