Description
- 判断下面代码能否通过编译
var(
size := 1024
max_size = size*2
)
func main() {
fmt.Println(size,max_size)
}
解析:变量声明的简短形式中,需要使用显示初始化,编译器会自动推导数据类型,所以不需要提供数据类型,只能在函数内部使用简短形式。
iota
的使用
const (
x = iota
_
y
z = "zz"
k
p = iota
)
func main() {
fmt.Println(x,y,z,k,p)
}
输出:
0 2 zz zz 5
解析:
-
iota
只在常量表达式中使用; -
每次
const
出现,都会让const
初始化为0
; -
自增常量经常包含一个自定义的枚举类型,允许依靠编译器完成自增设置;
-
使用
_
跳过不需要的值; -
定义在一行的情况:
const (
Apple, Banana = iota +1, iota + 2
Cherimoya, Durian
Elderberry, Fig
)
上面变量的结果如下:
Apple: 1
Banana: 2
Cherimoya: 2
Durian: 3
Elderberry: 3
Fig: 4
- 中间插队:
const (
i = iota
j = 3.14
k = iota
l
)
上面各个变量对应的结果就是0, 3.14, 2, 3
。
- 下面的赋值是否正确
var x error = nil
解析:nil
只能赋值给指针、chan
、func
、interface
、map
或slice
。
error
的定义如下:
type error interface {
Error() string
}
- 下面代码的输出是什么
func hello() []string {
return nil
}
func main() {
h := hello
if h == nil {
fmt.Println("nil")
} else {
fmt.Println("not nil")
}
}
输出:not nil
解析:h
是hello()
,所以其不为空,能通过编译。
iota
和const
关键字
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
在 const
关键字出现时将被重置为 0
,const
中每新增一行常量声明将使 iota
计数一次。
- 下面这段代码输出什么
type Direction int
const (
North Direction = iota
East
South
West
)
func (d Direction) String() string {
return [...]string{"North", "East", "South", "West"}[d]
}
func main() {
fmt.Println(South)
}
输出:South
解析:根据 iota
的用法推断出 South
的值是 2
;另外,如果类型定义了 String()
方法,当使用 fmt.Printf()
、fmt.Print()
和 fmt.Println()
会自动使用 String()
方法,实现字符串的打印。
- 下面这段代码输出什么
var p *int
func foo() (*int, error) {
var i int = 5
return &i, nil
}
func bar() {
//use p
fmt.Println(*p)
}
func main() {
p, err := foo()
if err != nil {
fmt.Println(err)
return
}
bar()
fmt.Println(*p)
}
解析:问题出在操作符:=
,对于使用:=
定义的变量,如果新变量与同名已定义的变量不在同一个作用域中,那么 Go
会新定义这个变量。对于本例来说,main()
函数里的 p
是新定义的变量,会遮住全局变量 p
,导致执行到 bar()
时程序,全局变量 p
依然还是 nil
,程序随即 Crash
。
- 下面代码输出什么
func main() {
i := 1
s := []string{"A", "B", "C"}
i, s[i-1] = 2, "Z"
fmt.Printf("s: %v \n", s)
}
输出:[Z, B, C]
解析:多重赋值时候,上例中,先计算等号左边的索引表达式和取值表达式,接着解读等号右边的表达式,然后进行赋值。所以赋值运算等同于 i, s[0] = 2, "Z"
。
-
i++
和i--
在Go
中是语句,不是表达式,所以不能进行赋值操作。 -
下面代码有什么问题
const i = 100
var j = 123
func main() {
fmt.Println(&j, j)
fmt.Println(&i, i)
}
结果:编译报错cannot take the address of i
解析:常量不同于变量的在运行期分配内存,常量通常会被编译器在预处理阶段直接展开,作为指令数据使用,所以常量无法寻址。
- 下面代码能否通过编译
func GetValue(m map[int]string, id int) (string, bool) {
if _, exist := m[id]; exist {
return "exist", true
}
return nil, false
}
func main() {
intmap := map[int]string{
1: "a",
2: "b",
3: "c",
}
v, err := GetValue(intmap, 3)
fmt.Println(v, err)
}
结果:不能通过编译。
解析:nil
可以用作 interface
、function
、pointer
、map
、slice
和 channel
的空值。但是如果不特别指定的话,Go
语言不能识别类型,所以会报错: cannot use nil as type string in return argument.
。
- 下面代码能否通过编译
func Foo(x interface{}) {
if x == nil {
fmt.Println("empty interface")
return
}
fmt.Println("non-empty interface")
}
func main() {
var x *int = nil
Foo(x)
}
输出:non-empty interface
解析:接口除了有静态类型,还有动态类型和动态值,当且仅当动态值和动态类型都为 nil
时,接口类型值才为 nil
。这里的 x
的动态类型是 *int
,所以 x
不为 nil
。
- 下面代码错误的地方
func main() {
var s []int
s = append(s,1)
var m map[string]int
m["one"] = 1
}
解析:不能对 nil
的 map
直接赋值,需要使用 make()
初始化。但可以使用 append()
函数对为 nil
的 slice
增加元素。
-
通过指针变量
p
访问其成员变量name
,有两种方式:p.name
和(*p).name
。 -
下面的代码有什么问题
func main() {
var x = nil
_ = x
}
解析:nil
用于表示 interface
、函数、maps
、slices
和 channels
的零值。如果不指定变量的类型,编译器猜不出变量的具体类型,导致编译错误。
修复代码:
func main() {
var x interface{} = nil
_ = x
}
- 下面代码输出什么
func test(x byte) {
fmt.Println(x)
}
func main() {
var a byte = 0x11
var b uint8 = a
var c uint8 = a + b
test(c)
}
解析:34
。与 rune
是 int32
的别名一样,byte
是 uint8
的别名,别名类型无须转换,可直接计算。
- 下面代码可以编译通过吗
func main() {
const x = 123
const y = 1.23
fmt.Println(x)
}
解析:编译可以通过。常量是一个简单值的标识符,在程序运行时,不会被修改的量。不像变量,常量未使用是能编译通过的。
- 下面代码输出什么
const (
x uint16 = 120
y
s = "abc"
z
)
func main() {
fmt.Printf("%T %v\n", y, y)
fmt.Printf("%T %v\n", z, z)
}
输出:
uint16 120
string abc
解析:常量组中如不指定类型和初始化值,则与上一行非空常量右值相同。
- 下面的代码输出什么
func (n N) value(){
n++
fmt.Printf("v:%p,%v\n",&n,n)
}
func (n *N) pointer(){
*n++
fmt.Printf("v:%p,%v\n",n,*n)
}
func main() {
var a N = 25
p := &a
p1 := &p
p1.value()
p1.pointer()
}
结果:编译错误。
calling method value with receiver p1 (type **N) requires explicit dereference
calling method pointer with receiver p1 (type **N) requires explicit dereference
解析:不能使用多级指针调用方法。