浅谈Go与习题(八)

100 阅读3分钟

开启掘金成长之旅!这是我参与「掘金日新计划 · 12 月更文挑战」的第31天,点击查看活动详情

今天来学习下Go常见的习题问题(八),也是面试中可能会遇到的,让我们来一起学习吧~

nil切片和空切片

观察下列两个切片的声明方式,有什么区别?

1. var w []int
2. w := []int{}

参考答案:第一个声明的形式是nil切片,第二个声明的形式是长度和容量都为0的空切片,第一个声明的方式不会被分配内存,优先选择

inerface{}类型

观察下列代码,是否可以通过编译?不可以的话,说明理由

type YYQQ struct {
}

func f(x interface{}) {
}

func g(x *interface{}) {
}

func main() {
    s := YYQQ{}
    p := &s
    f(s) 
    g(s) 
    f(p) 
    g(p) 
}

参考答案:不能通过编译,g(s) g(p)不能通过编译,因为g函数定义的是*interface{}类型的指针,如果参数是interface{}是可以接收任意类型的参数,包括用户自定义的类型,就算是指针类型也可以用interface{}接收,这里需要注意的是,不要将一个指针指向一个接口类型,因为它本身就是一个指针

指针类型

观察下列代码,划线部分应该填入什么,才可以保证输出结果为YYQQ

type S struct {
    m string
}

func f() *S {
    return __  //A
}

func main() {
    p := __    //B
    fmt.Println(p.m) //print "YYQQ"
}

参考答案:A处应该填入&S{"YYQQ"},B处应该填入*f()或者f(),因为f()函数返回的值结构体S的指针类型,所以要用取地址符&取结构体的指针,第二处如果填*f()取到的是S类型,如果填f()取到的是*P类型,但这两种都可以通过p.m取到结构体的成员

字符串赋值

观察下列代码,是否可以通过编译?如果可以,输出结果

package main
import (
    "fmt"
)
func main() {
    var x string = nil
    if x == nil {
        x = "YYQQ"
    }
    fmt.Println(x)
}

参考答案:不能通过编译,因为go语言中的string类型是不能赋值nil,也不能和nil进行比较

切片操作

观察下列代码,输出结果是什么?为什么?

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

参考答案:两次输出的结果都是[1 2 4],因为切片底层数据结构是数组,s2通过s1进行截取获得,和s1共享同一个底层数组,那么就会导致s2修改会影响s1的值,但是append操作会导致底层数组扩容,生成新的数组,所以后续追加的值不会影响s1,如果再修改s2也同样不会改变s1的值

image.png

map输出

观察下列代码,输出结果是什么?

func main() {
    m := map[int]string{0:"zero",1:"one"}
    for k,v := range m {
        fmt.Println(k,v)
    }
}

参考答案:

0 zero
1 one
// 或者
1 one
0 zero

因为map是无序输出,受到无序写入和扩容的影响,正常写入:虽然buckets是一块连续的内存,但是每次写入都会通过hash到记录到某一个bucket上,而不是按buckets顺序写入, 哈希冲突写入:如果存在hash冲突,会写到同一个bucket上,导致数据的错误,map扩容有两种成倍扩容和等量扩容

总结

今天浅谈了Go的习题(八),主要介绍了GO面试中会出现的问题,接下来会继续分享其他的习题的相关知识,对于一个刚入门的我来说,还有许多地方需要学习,有错误的地方欢迎大家指出,共同进步!!