最近看见一篇关于go基础的问题,算是给自己的一个小考验,很多基础的东西当你回过头来看看也许有新的认识,当然这些题也适合出面试题。
Quiz1
package main
import (
"fmt"
)
func hello() []string {
return nil
}
func main() {
h := hello // 这里注意区分 hello()
if h == nil {
fmt.Println("nil")
} else {
fmt.Println("not nil")
}
hs := hello() // 这里注意区分 hello
if hs == nil {
fmt.Println("nil")
} else {
fmt.Println("not nil")
}
}
// Answer:
// not nil
// nil
// We assign the function hello() to the variable h in line no. 12 and
// hence h is not nil and the program will print not nil.
Quiz2
package main
import (
"fmt"
"strconv"
)
func main() {
i := 2
s := "1000"
if len(s) > 1 { // 注意 变量的作用域
i, _ := strconv.Atoi(s) // 注意这里的是 := 而不是 =
i = i + 5
}
fmt.Println(i)
}
// Answer
// 2
// The tricky part of the above quiz is line no. 12. i, _ := strconv.Atoi(s) creates a new variable i whose scope is only within the if statement.
// The i which is being printed in line no. 15 is actually the one defined in line no. 9
// and not the one defined in line no. 12. Hence this program will print 2.
Quiz3
package main
import (
"fmt"
)
func hello(num ...int) {
num[0] = 18
}
func main() {
i := []int{5, 6, 7}
hello(i...) // go 中函数参数都是值传递,但对于slice也把地址传入,所谓的引用类型。
fmt.Println(i[0])
}
// Answer
// 18
Quiz4
package main
import (
"fmt"
)
func main() {
a := [2]int{5, 6}
b := [2]int{5, 6}
if a == b {
fmt.Println("equal")
} else {
fmt.Println("not equal")
}
}
// Answer
// equal
这道题目中对比的是数组,如果换成切片呢?
提示:切片不能用 == 进行比较,可以 进行判断 == nil
Quiz5 ⭐️
package main
import "fmt"
type rect struct {
len, wid int
}
func (r rect) area() {
fmt.Println(r.len * r.wid)
r.len = r.len + 1
}
func (r *rect) add() {
fmt.Println(r.len + r.wid)
r.len = r.len + 1
}
func main() {
r := &rect{len: 5, wid: 6}
r.area()
fmt.Println(r.len) // 5 没变
a := rect{len: 5, wid: 6}
a.add()
fmt.Println(a.len) // 6 改变
}
// Answer
// 30
// 5
// 11
// 6
// You might be wondering why the program worked when we didn't use (*r).area() in line no. 21. Since area() has a value receiver,
// Go is intelligent enough to interpret r.area() as (*r).area() and hence this program works :).
// 但只有当方法的接受者为指针形式时,才能够在方法内部进行属性操作生效从而改变源数据。反之则不能
Quiz6
package main
import (
"fmt"
)
func main() {
a := [5]int{1, 2, 3, 4, 5} // 这里是 array
t := a[3:4:4] // 这里就成了 slice len == 4-3 cap == 4-3
fmt.Println(t[0])
fmt.Println(len(t), cap(t))
}
// Answer
// 4
// 1 1
// a[low : high : max]
// constructs a slice of the same type,
// and with the same length and elements as the simple slice expression a[low : high].
// Additionally, it controls the resulting slice's capacity by setting it to max - low.
// Hence, the slice t in line no.9 has one element 4 and is of capacity 1.
Quiz7 ⭐️
package main
import (
"fmt"
"safeuem/common/log"
)
type person struct {
name string
}
func main() {
var m map[person]int // 注意这里用 var 和 make 的区别
p := person{"mike"}
fmt.Println(m[p])
v, ok := m[p]
log.Error(v, ok)
log.Error(m == nil)
log.Errorf("%p", m)
}
// Answer
// 0
// 0 false
// true
// 0x0
// var 并没有给变量分配控制内存地址,但是对于的值已经初始化为类型零值
Quiz8
package main
import (
"fmt"
"safeuem/common/log"
"strconv"
)
func main() {
i := 65
fmt.Println(string(i))
s := strconv.FormatInt(int64(i), 10) // string与其他类型之间的转换 应该使用 strconv 包
log.Error(s)
}
// Answer
// A
// 65
// The unicode value of A is 65.
// Hence when i is type casted to string in line no. 9, A is printed.
Quiz9 ⭐️
package main
import (
"fmt"
)
func main() {
var i interface{} // 注意 var 声明方式 不会分配内存地址 但会初始化对于类型的零值
if i == nil {
fmt.Println("nil")
return
}
fmt.Println("not nil")
}
// Answer
// nil
// An empty interface has both its underlying value and concrete type as nil. Hence i is nil
这道题,请自行查看interface 与 nil 的知识点
Quiz10 ⭐️
package main
import (
"fmt"
)
func hello(i int) {
fmt.Println(i)
}
func main() {
i := 5
defer hello(i) // defer 函数的参数 是在声明时进行读入值,而不是在实际调用时才读入
i = i + 10
}
// Answer
// 5
// The arguments of a deferred function are evaluated
// when the defer statement is executed and not when the actual function call is done.
// Hence when the defer statement is encountered in line no. 12, the value of i is 5.
// So this program will print 5.
这道题关于defer其中一个知识点,关于defer的知识点还有其他,自行查看吧。
Quiz11
package main
import (
"fmt"
)
func main() {
fmt.Printf("%%") // 输出 % 本体
}
// Answer
// %
// The format specifier %% prints a literal % sign. Hence the program prints %.
这里直接补充下:
动 词 | 功 能 |
---|---|
%v | 按值的本来值输出 |
%+v | 在 %v 基础上,对结构体字段名和值进行展开 |
%#v | 输出 Go 语言语法格式的值 |
%T | 输出 Go 语言语法格式的类型和值 |
%% | 输出 % 本体 |
%b | 整型以二进制方式显示 |
%o | 整型以八进制方式显示 |
%d | 整型以十进制方式显示 |
%+d | 整型以十进制方式显示并显示数字的符号 |
%x | 整型以十六进制方式显示 |
%X | 整型以十六进制、字母大写方式显示 |
%U | Unicode 字符 |
%f | 浮点数 |
%p | 指针,十六进制方式显示 |
Quiz12
package main
import (
"fmt"
)
func main() {
s := make(map[string]int)
delete(s, "h")
fmt.Println(s["h"])
}
// Answer
// 0
// The delete function in line no. 9 doesn't return anything and will do nothing if the specified key doesn't exist.
// Since the key h doesn't exist,
// the delete function will not do anything. In line no. 10, we are trying to print s["h"].
// Since the map s doesn't have the key h, it will return the default value of int. Hence 0 will be printed.
Quiz13
package main
import (
"fmt"
)
func main() {
i := -5
j := +5
fmt.Printf("%+d %+d", i, j) // +d 表示始终打出数字的符号
}
// Answer
// -5 +5
// The + flag in the format specifier %+d is used to always print a sign for numeric values.
// Hence this program outputs -5 +5.