TalkGo Night项目Golang面试题深度解析(二)

TalkGo Night项目Golang面试题深度解析(二)

night talkgo/nighthawk 是一个用于编写高性能 HTTP 服务器的 Go 语言库。适合在 Go 语言开发的应用程序中实现 RESTful API 和 Web 服务。特点是提供了简洁的 API、高性能的并发处理和高可扩展性。 night 项目地址: https://gitcode.com/gh_mirrors/ni/night

前言

本文将对TalkGo Night项目中精选的Golang面试题进行深入解析,这些题目涵盖了Go语言中容易混淆和出错的知识点,包括类型断言、函数返回值、defer机制、切片操作、结构体比较等多个方面。通过详细解析这些题目,帮助读者深入理解Go语言的特性。

1. 类型断言与接口类型检查

func main() {
    i := GetValue()
    switch i.(type) {
    case int:
        println("int")
    case string:
        println("string")
    case interface{}:
        println("interface")
    default:
        println("unknown")
    }
}

func GetValue() int {
    return 1
}

解析: 这个题目考察的是Go语言的类型断言机制。在Go中,.(type)语法只能用于接口类型(interface{})的变量上进行类型判断。题目中GetValue()返回的是具体类型int,而不是接口类型,因此编译会失败。

正确做法: 如果需要使用类型断言,应该先将返回值转换为接口类型:

var i interface{} = GetValue()
switch i.(type) {
// ...
}

2. 函数返回值的命名规则

func funcMui(x,y int)(sum int,error){
    return x+y,nil
}

解析: 这道题考察函数返回值的命名规则。在Go语言中:

  1. 如果函数有多个返回值,当其中一个返回值有命名时,其他返回值也必须命名
  2. 多个返回值必须用括号括起来
  3. 即使只有一个命名返回值,也需要用括号括起来

正确写法

func funcMui(x, y int) (sum int, err error) {
    return x + y, nil
}

3. defer与函数返回值的关系

func DeferFunc1(i int) (t int) {
    t = i
    defer func() {
        t += 3
    }()
    return t
}

func DeferFunc2(i int) int {
    t := i
    defer func() {
        t += 3
    }()
    return t
}

func DeferFunc3(i int) (t int) {
    defer func() {
        t += i
    }()
    return 2
}

解析: 这道题考察defer语句对函数返回值的影响,需要理解几个关键点:

  1. 命名返回值的作用域是整个函数
  2. defer语句在return之后执行,但在函数返回前执行
  3. 对于命名返回值,defer可以修改返回值
  4. 对于非命名返回值,return的值会被复制到一个临时变量,defer修改原变量不影响返回值

执行结果

  • DeferFunc1(1) 返回4(命名返回值t被defer修改)
  • DeferFunc2(1) 返回1(非命名返回值不受defer影响)
  • DeferFunc3(1) 返回3(return 2后,defer将t += 1)

4. new与make的区别

func main() {
    list := new([]int)
    list = append(list, 1)
    fmt.Println(list)
}

解析: 这道题考察newmake的区别:

  1. new只分配内存并返回指针,不初始化内存
  2. make用于slice、map和channel的初始化,返回已初始化的对象
  3. new([]int)返回的是指向nil slice的指针,不能直接用于append

正确做法

list := make([]int, 0)
list = append(list, 1)

5. 切片追加的正确用法

func main() {
    s1 := []int{1, 2, 3}
    s2 := []int{4, 5}
    s1 = append(s1, s2)
    fmt.Println(s1)
}

解析: 这道题考察切片的append操作。append一个切片到另一个切片时,需要使用...展开操作符。

正确写法

s1 = append(s1, s2...)

6. 结构体的比较规则

sn1 := struct {
    age  int
    name string
}{age: 11, name: "qq"}

sm1 := struct {
    age int
    m   map[string]string
}{age: 11, m: map[string]string{"a": "1"}}

解析: 这道题考察结构体的比较规则:

  1. 只有相同类型的结构体才能比较(字段名、类型、顺序都必须相同)
  2. 结构体中不能包含不可比较的类型(如map、slice、function)
  3. 可以使用reflect.DeepEqual进行深度比较

关键点

  • sn1和相同类型的结构体可以比较
  • sm1包含map字段,不能直接比较

7. 接口与nil的判断

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

解析: 这道题考察接口与nil的关系。接口变量包含类型和值两部分,只有当两者都为nil时,接口才等于nil。

输出结果non-empty interface,因为x是*int类型的nil值,接口变量包含类型信息。

8. 函数返回值的类型一致性

func GetValue(m map[int]string, id int) (string, bool) {
    if _, exist := m[id]; exist {
        return "存在数据", true
    }
    return nil, false
}

解析: 这道题考察函数返回值的类型一致性。nil不能直接作为string类型的返回值,因为nil只能用于特定类型(interface、pointer、map、slice等)。

正确写法

return "", false

9. iota常量生成器的使用

const (
    x = iota
    y
    z = "zz"
    k
    p = iota
)

解析: 这道题考察iota的用法:

  1. iota在const声明块中从0开始递增
  2. 每次const关键字出现时重置为0
  3. 省略值会沿用上一个表达式,但iota仍然递增
  4. 显式赋值会中断iota递增,但iota计数器继续增加

输出结果: 0 1 zz zz 4

总结

本文通过9个典型面试题的解析,深入探讨了Go语言中的多个重要概念。理解这些知识点对于编写正确、高效的Go代码至关重要。建议读者在理解这些题目后,可以自己尝试编写类似的测试代码,加深对Go语言特性的理解。

night talkgo/nighthawk 是一个用于编写高性能 HTTP 服务器的 Go 语言库。适合在 Go 语言开发的应用程序中实现 RESTful API 和 Web 服务。特点是提供了简洁的 API、高性能的并发处理和高可扩展性。 night 项目地址: https://gitcode.com/gh_mirrors/ni/night

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

吉生纯Royal

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值