Golang 基礎(chǔ)面試高頻題總匯【第一版】來啦~

Golang基礎(chǔ)題

1削祈、下面這段代碼的輸出什么饰抒?

func main() {
    defer func() { fmt.Println("打印前") }()
    defer func() { fmt.Println("打印中") }()
    defer func() { fmt.Println("打印后") }()
    panic("觸發(fā)異常")
}

輸出:
打印后
打印中
打印前
panic: 觸發(fā)異常
......

解析:協(xié)程遇到panic時肮砾,遍歷本協(xié)程的defer鏈表(defer 是一個鏈表的結(jié)構(gòu),新的defer會被追加到defer鏈表的最前面袋坑,可理解為后進先出)仗处,并執(zhí)行defer。在執(zhí)行defer過程中枣宫,遇到recover則停止panic婆誓,返回recover處繼續(xù)往下執(zhí)行掐禁。如果沒有遇到recover著榴,遍歷完本協(xié)程的defer鏈表后,向stderr拋出panic信息

2队秩、下面代碼會輸出什么翅娶?

func calc(index string, a, b int) int {
    ret := a + b
    fmt.Println(index, a, b, ret)
    return ret
}
 
func main() {
    a := 1
    b := 2
    defer calc("1", a, calc("10", a, b))
    a = 0
    defer calc("2", a, calc("20", a, b))
    b = 1
}

輸出:
10 1 2 3
20 0 2 2
2 0 2 2
1 1 3 4

解析:這里需要注意的是文留,當(dāng)執(zhí)行到defer定義時,首先會對參數(shù)進行求值竭沫,然后參數(shù)被壓入函數(shù)調(diào)用棧燥翅,此時不會進入defer函數(shù)體,而是直到函數(shù)返回時才調(diào)用defer函數(shù)體蜕提。參數(shù)被壓入函數(shù)調(diào)用棧時森书,如果參數(shù)是值類型,那么將復(fù)制值,如果參數(shù)是指針凛膏,那么將復(fù)制指針而不是復(fù)制指針指向的值杨名。

3、下面代碼輸出什么猖毫?

func main() {
    slice := []int{0, 1, 2, 3}
    m := make(map[int]*int)

    for key, val := range slice {
        m[key] = &val
    }

    for k, v := range m {
        fmt.Printf("key: %d, value: %d \n", k, *v)
    }
}

輸出:
key: 0, value: 3
key: 1, value: 3
key: 2, value: 3
key: 3, value: 3

解析:整個循環(huán)中镣煮,val都是同一個全局變量(與for range 結(jié)構(gòu)有關(guān)),地址是一樣的鄙麦,每次遍歷該地址上的值都會被新的值覆蓋掉典唇,所以在遍歷結(jié)束后,該地址存的值是切片上的最后一個元素3胯府。具體for range 坑點可以參考這篇文章Golang 之 我被 for-range 循環(huán)進去了

4介衔、下面代碼會輸出什么

func main() {
    i := make([]int, 5)
    i = append(i, 1, 2, 3)
    fmt.Println(i)

    j := make([]int, 0)
    j = append(j, 1, 2, 3, 4)
    fmt.Println(j)
}

輸出:
[0 0 0 0 0 1 2 3]
[1 2 3 4]

解析:make函數(shù)創(chuàng)建切片時,如果有指定長度骂因,則分配一個指定長度的數(shù)組炎咖,初始化值為0,并返回一個引用該數(shù)組的slice

5寒波、下面這段代碼有錯誤嗎乘盼?

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

解析:第二個返回值沒有命名,在函數(shù)有多個返回值時俄烁,只要有一個返回值有命名绸栅,其他的也必須命名。如果有多個返回值必須加上括號 ()页屠;如果只有一個返回值且命名也必須加上括號 ()粹胯。這里的第一個返回值有命名 sum,第二個沒有命名辰企,所以錯誤风纠。

6、new() 和 make() 的區(qū)別

解析:new 和 make的區(qū)別:

  • new 返回的是指向類型的指針牢贸,即類型 *Type竹观;make 返回的還是引用類型本身;
  • new 分配的空間被清零潜索,也就是類型的零值(int類型的零值是0臭增,string類型的零值是"",引用類型的零值是nil)帮辟。make 分配空間后速址,會進行初始化;
  • new 可以分配任意類型的數(shù)據(jù)由驹,make 只能用來分配及初始化類型為 slice芍锚、map昔园、chan 的數(shù)據(jù)

7、下面代碼能否編譯通過并炮,如果能默刚,輸出什么?

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

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

> 解析:編譯錯誤

首先 new([]int) 之后的 list 是一個 *[]int 類型的指針逃魄,不能對指針執(zhí)行append操作荤西;
再看 s1 = append(s1, s2),編譯失敗伍俘,追加一個切片邪锌,切片需要解包,正確姿勢是:s1 = append(s1, s2...)

8癌瘾、下面代碼能否編譯通過

func Test7(t *testing.T) {
    sn1 := struct {
        age  int
        name string
    }{age: 11, name: "qq"}
    sn2 := struct {
        age  int
        name string
    }{age: 11, name: "qq"}
    
    // 可以比較
    if sn1 == sn2 {
        fmt.Println("sn1 == sn2")
    }

    sm1 := struct {
        age int
        m   map[string]string
    }{age: 11, m: map[string]string{"a": "1"}}
    sm2 := struct {
        age int
        m   map[string]string
    }{age: 11, m: map[string]string{"a": "1"}}
    // 編譯錯誤觅丰,map不能進行比較
    if sm1 == sm2 {
        fmt.Println("sm1 == sm2")
    }
}

解析:
詳細解析可參考文章:golang之struct能不能比較

9、通過指針變量 p 訪問其成員變量 name妨退,有哪幾種方式妇萄?

A. p.name

B. (&p).name

C. (*p).name

D. p->name

答案:AC

10、關(guān)于字符串連接咬荷,下面語法正確的是

A. str := 'abc' + '123'

B. str := "abc" + "123"

C. str := '123' + "abc"

D. fmt.Sprintf("abc%d", 123)

答案:BD

11冠句、關(guān)于iota,下面代碼會輸出什么幸乒?

func main() {
    const (
        x = iota
        _
        i
        j
        y
        z = "aa"
        o
        k = iota
        p
        q
    )
    fmt.Println(x,i,j, y, z,o, k, p, q)
}

輸出:
0
2
3
4
aa
aa
7
8
9

解析:iota 初始值為0懦底,往下進行自增1 進行賦值,遇到自定義賦值的常量逝变,則對當(dāng)前常量進行自定義賦值基茵,后面常量的值跟當(dāng)前常量的值一致,直到又遇到自定義賦值的常量壳影,在這個過程中iota一直保持自增狀態(tài)

12、下面賦值正確的是

A. var x = nil

B. var x interface{} = nil

C. var x string = nil

D. var x error = nil

答案:BD

13弥臼、關(guān)于channel宴咧,下面語法正確的是?

A. var ch chan int

B. ch := make(chan int)

C. <- ch

D. ch <-

答案:ABC

解析:往channel寫數(shù)據(jù)時径缅,<- 右端必須要有值

14掺栅、下面代碼輸出什么?

func hello (num ...int) {
    num[0] = 18
}

func main() {
    i := []int{5, 6, 7}
    hello(i...)
    fmt.Println(i[0])
}
A.18

B.5

C.Compilation error

答案:18

解析:func hello (num ...int) 為函數(shù)傳入可變參數(shù)的表達式纳猪。...type本質(zhì)上是一個數(shù)組切片氧卧,也就是[]type,切片作為函數(shù)參數(shù)傳的是指針拷貝氏堤,具體的坑點可參考文章:(正經(jīng)版)面試官:切片作為函數(shù)參數(shù)是傳值還是傳引用沙绝?

15、下面選擇哪個?

func main() {  
    a := 5
    b := 8.1
    fmt.Println(a + b)
}

A.13.1

B.13

C.compilation error

答案:C

解析:整型和浮點型不能相加

16闪檬、下面代碼輸出什么星著?

func Test15(t *testing.T) {
    a := [5]int{1, 2, 3, 4, 5}
    s := a[3:4:4]
    fmt.Println(s[0])
}

答案:4

解析:a[low : high : max],其中由 a[low : high] 生成切片粗悯,切片的容量等于(max - low)

17虚循、下面代碼輸出什么?

func main() {
    a := [2]int{5, 6}
    b := [3]int{5, 6}
    if a == b {
        fmt.Println("equal")
    } else {
        fmt.Println("not equal")
    }
}

A. compilation error

B. equal

C. not equal

答案:A

解析:數(shù)組的比較的前提是兩者要有相同的長度

18样傍、下列哪個類型可以使用cap() 函數(shù)

A. array

B. slice

C. map

D. channel

答案:ABD

解析:cap()函數(shù)只支持 數(shù)組(array)横缔,數(shù)組指針(*array),切片(slice)衫哥,通道(channel)

19剪廉、下面代碼輸出什么?

func main() {
    var i interface{}
    if i == nil {
        fmt.Println("nil")
        return
    }
    fmt.Println("not nil")
}

答案:nil

解析:引用類型的零值為 nil, 常見的引用類型有: point, function, interface, slice, channel, map
bool 的零值為 false炕檩;整數(shù)的零值為 0斗蒋;浮點數(shù)的零值為 0.0;string 的零值為 空字符串 ""

20笛质、下面代碼輸出什么泉沾?

func main() {
    s := make(map[string]int)
    delete(s, "h")
    fmt.Println(s["h"])
}

答案:0

解析:使用內(nèi)置函數(shù)delete刪除map的鍵值對時,如果map為nil 或者鍵值對不存在時妇押,delete不會做任何操作跷究,程序不會報錯;獲取不存在的鍵值對時敲霍,返回值為對應(yīng)類型的零值俊马,所以返回0

21、下面代碼輸出什么肩杈?

func main() {
    i := -5
    j := +5
    fmt.Printf("%+d %+d", i, j)
}

答案:-5 +5

解析:%+d 是帶符號輸出

22柴我、定義一個全局字符串變量,下列正確的是扩然?

A. var str string

B. str := ""

C. str = ""

D. var str = ""

答案:AD

解析:B選項只支持局部變量聲明艘儒;C是賦值語句,str 必須在這之前就已經(jīng)聲明

23夫偶、下面代碼輸出什么界睁?

func f(i int) {
    fmt.Println(i)
}

func main() {
    i := 5
    defer f(i)

    i += 10
}

答案:5

解析:f() 函數(shù)的參數(shù)在執(zhí)行defer語句的時候會保存一份副本,在實際調(diào)用f()函數(shù)時使用兵拢,所以是5

24翻斟、下面代碼輸出什么?

func main() {
    str := "hello"
    str[0] = 'x'
    fmt.Println(str)
}

A. hello

B. xello

C. compilation error

答案:C 編譯錯誤

解析:Golang中说铃,字符串是只讀的访惜,可以打印嘹履,如 fmt.Println(str[0]),不可修改

25疾牲、關(guān)于可變參數(shù)的函數(shù)調(diào)用正確的是植捎?

func add(args ...int) int {

    sum := 0
    for _, arg := range args {
        sum += arg
    }
    return sum
}

A. add(1, 2)

B. add(1, 3, 7)

C. add([]int{1, 2})

D. add([]int{1, 3, 7}…)

答案:ABD

解析:可變參數(shù)如果是切片,必須是 []type{}... 格式阳柔,別問焰枢,問就是規(guī)定的

26、下面代碼填入哪個變量會輸出 yes nil

func main() {
    var s1 []int
    var s2 = []int{}
    if ___ == nil {
        fmt.Println("yes nil")
    } else {
        fmt.Println("no nil")
    }
}

答案:s1

解析:s1 表示nil切片(切片的零值)nil 切片和 nil 相等舌剂;s2 表示空切片济锄,表示一個空的集合,和nil不相等

27霍转、下面代碼會輸出什么荐绝?

func main() {
    i := 65
    fmt.Println(string(i))
}

A. A

B. 65

C. compilation error

答案:A

解析:UTF-8編碼中,十進制數(shù)字65對應(yīng)的符號是A

28避消、切片 a低滩,b,c 的容量分別是多少岩喷?

func main() {
    s := [3]int{1, 2, 3}
    a := s[:0]
    b := s[:2]
    c := s[1:2:cap(s)]
    fmt.Println(cap(a))
    fmt.Println(cap(b))
    fmt.Println(cap(c))
}

答案:
3
3
2

解析:數(shù)組的容量等于數(shù)據(jù)的長度恕沫,s[a:b:c] 容量計算可以參考第16題,切片容量計算可參考文章:(正經(jīng)版)面試官:切片作為函數(shù)參數(shù)是傳值還是傳引用纱意?

29婶溯、下面代碼輸出什么?

func increaseA() int {
    var i int
    defer func() {
        i++
    }()
    return i
}

func increaseB() (r int) {
    defer func() {
        r++
    }()
    return r
}

func main() {
    fmt.Println(increaseA())
    fmt.Println(increaseB())
}

答案:
0
1

解析:參考文章:關(guān)于defer坑坑洼洼的使用細節(jié)你mark了嗎

30偷霉、函數(shù) f1()迄委,f2(),f3() 分別返回什么类少?

func f1() (r int) {
    defer func() {
        r++
    }()
    return 0
}

func f2() (r int) {
    t := 5
    defer func() {
        t = t + 5
    }()
    return t
}

func f3() (r int) {
    defer func(r int) {
        r = r + 5
    }(r)
    return 1
}

func main() {
    fmt.Println(f1())
    fmt.Println(f2())
    fmt.Println(f3())
}

答案:
1
5
1

解析:參考文章:關(guān)于defer坑坑洼洼的使用細節(jié)你mark了嗎

31叙身、下面代碼輸出什么?

type Person struct {
    age int
}

func main() {
    person := &Person{28}

    defer fmt.Printf("輸出1:%v\n", person.age)

    defer func(p *Person) {
        fmt.Printf("輸出2:%v\n", p.age)
    }(person)

    defer func() {
        fmt.Printf("輸出3:%v\n", person.age)
    }()

    person.age = 29
}

答案:
輸出3:29
輸出2:29
輸出1:28

解析:
輸出3作為閉包引用瞒滴,所以輸出29
輸出2作為函數(shù)參數(shù)曲梗,相當(dāng)于變量拷貝,這里是指針變量的拷貝妓忍,指針變量的值依然是指向原有變量的地址,因此最終會輸出29
輸出1作為函數(shù)參數(shù)愧旦,在 defer 定義時就把值傳遞給 defer 函數(shù)體緩存起來世剖,因此輸出28

32、下面的兩個切片聲明中有上面區(qū)別笤虫?哪個更可扰蕴薄祖凫?

A. var a []int

B. a := []int{}

答案:A

解析:
A 聲明的是 nil 切片;
B 聲明的是長度和容量都為 0 的空切片酬凳。
A 的聲明不會分配內(nèi)存惠况,優(yōu)先選擇

33、A宁仔、B稠屠、C、D 哪個有語法錯誤

type S struct {
}

func m(x interface{}) {
}

func g(x *interface{}) {
}

func main() {
    s := S{}
    p := &s
    m(s) //A
    g(s) //B
    m(p) //C
    g(p) //D
}

答案:B翎苫、D 會編輯錯誤

解析:函數(shù)參數(shù)為 interface {} 時可以接收任何類型的參數(shù)权埠,包括用戶自定義類型等,
即使是接收指針類型也用 interface {}煎谍,而不是使用 *interface {}
永遠不要使用一個指針指向一個接口類型攘蔽,因為它已經(jīng)是一個指針。

34呐粘、下面代碼輸出什么满俗?

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]
[1 2 4]

解析:相信看過大叔之前文章的同學(xué)一下就能回答上來,不贅述作岖,附上文章鏈接:(正經(jīng)版)面試官:切片作為函數(shù)參數(shù)是傳值還是傳引用唆垃?

35、下列代碼輸出什么鳍咱?

func main() {
    if a := 1; false {
        
    } else if b := 2; false {
    
    } else {
        fmt.Println(a, b)
    }
}

答案:1 2

解析:if 語句聲明變量降盹,該變量的作用域只屬于整個 if block 結(jié)構(gòu)

36、下面代碼輸出什么

func calc(index string, a, b int) int {
    ret := a + b
    fmt.Println(index, a, b, ret)
    return ret
}

func main() {
    a := 1
    b := 2
    defer calc("A", a, calc("10", a, b))
    a = 0
    defer calc("B", a, calc("20", a, b))
    b = 1
}

答案:
10 1 2 3
20 0 2 2
B 0 2 2
A 1 3 4

解析:參考文章:關(guān)于defer坑坑洼洼的使用細節(jié)你mark了嗎

37谤辜、下列代碼輸出什么

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

答案:
1 one
0 zero

0 zero
1 one

解析:map 輸出是無序的

38蓄坏、下面代碼能否正常打印輸出

type People interface {
    Speak(string)
}

type Student struct{}

func (stu *Student) Speak(think string) {
    fmt.Println(think)
}

func main() {
    var peo People 
    student := Student{}
    peo = student
    
    peo.Speak("speak")
}

答案:編譯失敗,Student does not implement People (Speak method has pointer receiver)

解析:
因為是 *Student 實現(xiàn)了接口 Speak丑念,并不是類型Student,
但是如果是 Student 類型實現(xiàn)了 Speak 方法涡戳,那么用 值類型的 Student{} 或是指針類型的 &Student{} 都可以訪問到該方法。

39脯倚、下面代碼輸出什么

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

解析:
1渔彰、每個常量塊(const block) 結(jié)構(gòu)體都會重置和初始化 iota 的值為 0,往后常量塊中每新增一行常量聲明 iota將自增 1
2推正、即便 iota 在常量塊(const block) 中并非是首行出現(xiàn)恍涂,iota 也會在首行進行初始化(值為 0),完后常量進行自增 1

40植榕、下面代碼輸出什么再沧?

func main() {
    const a = iota              
    const b = iota + 3          
    const c, d = iota, iota + 3 
    const (
        e = iota     // e=0
        f = iota + 4 // f=5
        g            // g=6
    )
    println(a, b, c, d, e, f, g)
}

答案:0 3 0 3 0 5 6

解析:參考38題

41、下面代碼輸出什么尊残?

type People interface {
    Show()
}

type Student struct{}

func (stu *Student) Show() {

}

func main() {
    var s *Student
    if s == nil {
        fmt.Println("s is nil")
    } else {
        fmt.Println("s is not nil")
    }
    var p People = s
    if p == nil {
        fmt.Println("p is nil")
    } else {
        fmt.Println("p is not nil")
    }
}

答案:
s is nil
p is not nil

解析:當(dāng)且僅當(dāng)動態(tài)值和動態(tài)類型都為 nil 時炒瘸,接口類型值才為 nil淤堵。上面的代碼,給變量 p 賦值之后顷扩,
p 的動態(tài)值是 nil拐邪,但是動態(tài)類型卻是 *Student,是一個 nil 指針隘截,所以相等條件不成立扎阶。

42、下面代碼輸出什么

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

解析:
在go中如果重寫了String 方法技俐,那在調(diào)用fmt.Println時就會自動去執(zhí)行 String 方法

43乘陪、下面代碼能夠正常輸出嗎

type Square struct {
    x, y int
}

var m = map[string]Square{
    "foo": Square{2, 3},
}

func main() {
    m["foo"].x = 1
    fmt.Println(m["foo"].x)
}

答案:編譯失敗

解析:
對于類似 X = Y 的賦值操作,必須知道 X 的地址雕擂,才能夠?qū)?Y 的值賦給 X啡邑,
但 go 中的 map 的 value 本身是不可尋址的。
正確的寫法有兩種:
第一種:

square := m["foo"]
square.x = 1

這種寫法無法修改 m["foo"] 中 x 變量的值> 第二種:

var m = map[string]*Square{
   "foo": &Square{2, 3},
}
m["foo"].x = 1

這種可以修改 m["foo"] 中 x 變量的值

44井赌、下面代碼輸出什么

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

答案:bar 函數(shù)會發(fā)生 panic谤逼,空指針異常

解析:因為 err 前面沒有聲明,所以 p, err := foo () 中的 p 是重新聲明的局部變量仇穗,而不是我們在前面聲明的全局變量 p

45流部、下面代碼輸出什么

func main() {
    v := []int{1, 2, 3}
    for i := range v {
        v = append(v, i)
        fmt.Println(v)
    }
}

答案:
[1 2 3 0]
[1 2 3 0 1]
[1 2 3 0 1 2]

解析:可參考文章:Golang 之 我被 for-range 循環(huán)進去了

46、下面代碼會輸出什么纹坐?

func main() {
    var m = [...]int{1, 2, 3}

    for i, v := range m {
        go func() {
            fmt.Println(i, v)
        }()
    }

    time.Sleep(time.Second * 1)
}

答案:
2 3
2 3
2 3\

解析:for range 使用短變量聲明 (:=) 的形式迭代變量枝冀,
需要注意的是,變量 i耘子、v 在每次循環(huán)體中都會被重用果漾,而不是重新聲明。詳細可參考文章:Golang 之 我被 for-range 循環(huán)進去了

47谷誓、下面代碼會輸出什么绒障?

func test(n int) (r int) {
    // 第一個defer
    defer func() {
        r += n
        recover()
    }()

    var f func()
    // 第二個defer
    defer f()
    f = func() {
        r += 2
    }
    return n + 1
}

func main() {
    fmt.Println(test(3))
}

答案:7
解析:
首先,defer 是和返回值被命名的函數(shù)一起使用的捍歪,而且 defer 語句定義時對外部變量引用的方式是閉包引用(細節(jié)可參考文章:關(guān)于defer坑坑洼洼的使用細節(jié)你mark了嗎户辱,建議先看完文章再往下看,否則有的同學(xué)可能會有點接不上)
為什么第二個 defer 不起作用呢糙臼?其實第二個 defer 的延遲函數(shù)啥都沒干庐镐,甚至程序執(zhí)行到 f() 時還拋出 panic 了。我們都知道 程序在執(zhí)行到 defer 定義時并不會馬上執(zhí)行变逃,而是對捕捉到的 defer 結(jié)果進行鏈表構(gòu)建焚鹊,把關(guān)聯(lián)的函數(shù)入棧緩存,在程序 return 前再進行出棧執(zhí)行韧献。那么問題就很明顯了末患,我們看在程序執(zhí)行到 defer f() 時,此時的 f 是啥锤窑?此時的 f 的值為 nil璧针,所以最后出棧執(zhí)行一個nil 函數(shù),就相當(dāng)于:

var f func()
f()    // panic: runtime error: invalid memory address or nil pointer dereference

因此這也是為什么第一個 defer 為什么要有 recover() 方法渊啰。后面的 f = func() { r += 2 } 是賦值操作探橱,對返回值 r 沒影響

48、下面代碼輸出什么

func test(n int) (r int) {
    // 第一個defer
    defer func() {
        r += n
    }()

    var f func()
    f = func() {
        r += 2
    }
    // 第二個defer
    defer f()
    return n + 1
}

func main() {
    fmt.Println(test(3))
}

答案:9
解析:參考47題

49绘证、下面代碼輸出什么

func main() {
    var a = [5]int{1, 2, 3, 4, 5}
    var r [5]int

    for i, v := range a {
        if i == 0 {
            a[1] = 12
            a[2] = 13
        }
        r[i] = v
    }
    fmt.Println("r = ", r)
    fmt.Println("a = ", a)
}

答案:
r = [1 2 3 4 5]
a = [1 12 13 4 5]\

解析:參考文章:Golang 之 我被 for-range 循環(huán)進去了

50隧膏、下面代碼輸出什么?

func main() {
    slice := make([]int, 5, 5)
    slice[0] = 1
    slice[1] = 2
    change(slice...)
    fmt.Println(slice)
    change(slice[0:2]...)
    fmt.Println(slice)
}

答案:
[1 2 0 0 0]
[1 2 3 0 0]

解析:參考文章:(正經(jīng)版)面試官:切片作為函數(shù)參數(shù)是傳值還是傳引用嚷那?

51胞枕、下面代碼輸出什么

func main() {
    var m = map[string]int{
        "A": 21,
        "B": 22,
        "C": 23,
    }
    counter := 0
    for k, v := range m {
        if counter == 0 {
            delete(m, "A")
        }
        counter++
        fmt.Println(k, v)
    }
    fmt.Println("counter is ", counter)
}

答案:
counter is 2 或者 counter is 3
for range map 是無序的

52、關(guān)于協(xié)程魏宽,下列說法正確的是

A. 協(xié)程和線程都可以實現(xiàn)程序的并發(fā)執(zhí)行腐泻;

B. 線程比協(xié)程更輕量級;

C. 協(xié)程不存在死鎖問題队询;

D. 通過 channel 來進行協(xié)程間的通信派桩;

答案:AD

53、關(guān)于循環(huán)語句蚌斩,下面說法正確的是

A. 循環(huán)語句既支持 for 關(guān)鍵字铆惑,也支持 while 和 do-while;

B. 關(guān)鍵字 for 的基本使用方法與 C/C++ 中沒有任何差異送膳;

C. for 循環(huán)支持 continue 和 break 來控制循環(huán)员魏,但是它提供了一個更高級的 break,可以選擇中斷哪一個循環(huán)肠缨;

D. for 循環(huán)不支持以逗號為間隔的多個賦值語句逆趋,必須使用平行賦值的方式來初始化多個變量;

答案:CD

解析:
C : golang中晒奕,goto語句可以無條件地轉(zhuǎn)移到過程中指定的行闻书,通常與條件語句配合使用∧曰郏可用來實現(xiàn)條件轉(zhuǎn)移魄眉, 構(gòu)成循環(huán),跳出循環(huán)體等功能闷袒。例如:

    func main() {
        for a:=0;a<5;a++{
            fmt.Println(a)
            if a>3{
                goto Loop
            }
        }
        Loop:           //放在for后邊
        fmt.Println("test")
    }

D:for 語句執(zhí)行變量平衡初始化

for i, j := 0, 5; i < j; i, j = i+1, j-1 {
      fmt.Println("hhh")
}

54坑律、下面代碼輸出什么?

func main() {
    i := 1
    s := []string{"A", "B", "C"}
    i, s[i-1] = 2, "Z"
    fmt.Printf("s: %v \n", s)
}

答案:s: [Z B C]

解析:golang運算符優(yōu)先級:
(+ 囊骤、-)> (=晃择、+=冀值、-=、*=宫屠、/=列疗、 %=、 >=浪蹂、 <<=抵栈、&=、^=坤次、|=)

55古劲、關(guān)于 switch 語句,下面說法正確的是

A. 條件表達式必須為常量或者整數(shù)缰猴;

B. 單個 case 中产艾,可以出現(xiàn)多個結(jié)果選項;

C. 需要用 break 來明確退出一個 case洛波;

D. 只有在 case 中明確添加 fallthrough 關(guān)鍵字胰舆,才會繼續(xù)執(zhí)行緊跟的下一個 case;

答案:BD

解析:
switch/case 后是一個表達式(即:常量蹬挤,變量缚窿,一個有返回的函數(shù)都可以);A 錯誤
無需用一個 break 來明確退出一個 case焰扳,B 錯

56倦零、下列 Add 函數(shù)定義正確的是:

func Test54(t *testing.T) {
    var a Integer = 1
    var b Integer = 2
    var i interface{} = &a
    sum := i.(*Integer).Add(b)
    fmt.Println(sum)
}

A.
type Integer int
func (a Integer) Add(b Integer) Integer {
        return a + b
}

B.
type Integer int
func (a Integer) Add(b *Integer) Integer {
        return a + *b
}

C.
type Integer int
func (a *Integer) Add(b Integer) Integer {
        return *a + b
}

D.
type Integer int
func (a *Integer) Add(b *Integer) Integer {
        return *a + *b
}

答案:AC

解析:Add()函數(shù)的參數(shù)應(yīng)該是 Integer 類型,BD錯誤

57吨悍、關(guān)于 bool 變量 b 的賦值扫茅,下面錯誤的用法是?

A. b = true

B. b = 1

C. b = bool(1)

D. b = (1 == 2)

答案:BC

解析:
golang 中 bool 類型變量的值只能是 true / false育瓜,B 錯誤
golang中沒有 bool(1) 這種強制轉(zhuǎn)換的表達方式葫隙,C 錯誤

58、關(guān)于變量的自增和自減操作躏仇,下面語句正確的是:

A
i := 1
i++

B
i := 1
j = i++

C
i := 1
++i

D
i := 1
i--

答案:AD

解析:golang 中沒有 ++i 或者 --i這種表達式恋脚,B 中 新變量 j 的聲明和初始化應(yīng)該使用 :=

59、關(guān)于 GetPodAction 定義焰手,下面賦值正確的是

type Fragment interface {
        Exec(transInfo *TransInfo) error
}
type GetPodAction struct {
}
func (g GetPodAction) Exec(transInfo *TransInfo) error {
        ...
        return nil
}

A. var fragment Fragment = new(GetPodAction)

B. var fragment Fragment = GetPodAction

C. var fragment Fragment = &GetPodAction{}

D. var fragment Fragment = GetPodAction{}

答案:ACD

60糟描、關(guān)于整型切片的初始化,下面正確的是

A. s := make([]int)

B. s := make([]int, 0)

C. s := make([]int, 5, 10)

D. s := []int{1, 2, 3, 4, 5}

答案:BCD

解析:使用內(nèi)置方法 make() 初始化切片時必須指定長度

61书妻、下面代碼是否會觸發(fā)異常

func main() {
    runtime.GOMAXPROCS(1)
    intChan := make(chan int, 1)
    stringChan := make(chan string, 1)
    intChan <- 1
    stringChan <- "hello"
    select {
    case value := <-intChan:
        fmt.Println(value)
    case value := <-stringChan:
        panic(value)
    }
}

答案:可能會船响,可能不會

解析:當(dāng)兩個 chan 同時有值時,即 select 中的 case 都匹配時,select 會隨機選擇一個可用通道做收發(fā)操作

62见间、關(guān)于 channel 的特性聊闯,下面說法正確的是

A. 給一個 nil channel 發(fā)送數(shù)據(jù),造成永遠阻塞

B. 從一個 nil channel 接收數(shù)據(jù)缤剧,造成永遠阻塞

C. 給一個已經(jīng)關(guān)閉的 channel 發(fā)送數(shù)據(jù)馅袁,引起 panic

D. 從一個已經(jīng)關(guān)閉的 channel 接收數(shù)據(jù),如果緩沖區(qū)中為空荒辕,則返回一個零值

答案:ABCD

解析:概念性的知識點玩命記就是了

63、下面代碼有什么問題:

const i = 100
var j = 123

func main() {
    fmt.Println(&j, j)
    fmt.Println(&i, i)
}

答案:編譯失斢贪:cannot take the address of i

解析:golang 中抵窒,常量無法尋址,是不能進行做指針操作的

64叠骑、下面代碼輸出什么李皇?

func main() {
    x := []string{"a", "b", "c"}
    for v := range x {
        fmt.Print(v)
    }
}

答案:012

解析:range 一個返回值時,這個值是下標(biāo)宙枷,兩個值時掉房,第一個是下標(biāo),第二個是值慰丛,當(dāng) x 為 map 時卓囚,第一個是 key,第二個是 value

65诅病、關(guān)于無緩沖和有緩沖的 channel哪亿,下面說法正確的是?

A. 無緩沖的 channel 是默認(rèn)的緩沖為 1 的 channel贤笆;

B. 無緩沖的 channel 和有緩沖的 channel 都是同步的蝇棉;

C. 無緩沖的 channel 和有緩沖的 channel 都是非同步的;

D. 無緩沖的 channel 是同步的芥永,而有緩沖的 channel 是非同步的篡殷;

答案:D

66、下面代碼輸出什么埋涧?

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

解析:
接口除了有靜態(tài)類型板辽,還有動態(tài)類型和動態(tài)值,
當(dāng)且僅當(dāng)動態(tài)值和動態(tài)類型都為 nil 時飞袋,接口類型值才為 nil戳气。
這里的 x 的動態(tài)類型是 *int,所以 x 不為 nil

67巧鸭、關(guān)于 select 機制瓶您,下面說法正確的是

A. select 機制用來處理異步 IO 問題;

B. select 機制最大的一條限制就是每個 case 語句里必須是一個 IO 操作;

C. golang 在語言級別支持 select 關(guān)鍵字呀袱;

D. select 關(guān)鍵字的用法與 switch 語句非常類似贸毕,后面要帶判斷條件;

答案:ABC

解析:
select后不用帶判斷條件夜赵,是case后帶判斷條件明棍。
select的用法與switch非常類似,由select開始一個新的選擇塊寇僧,每個選擇條件由case語句來描述摊腋。與switch語句可以選擇任何可使用相等比較的條件相比,select有比較多的限制嘁傀,其中最大的一條限制就是每個case語句里必須是一個IO操作兴蒸,確切的說,應(yīng)該是一個面向channel的IO操作细办。

68橙凳、下面代碼有什么問題

func Stop(stop <-chan bool) {
        close(stop)
}
func main() {
    c := make(chan bool)
    Stop(c)
}

答案:編譯失敗:invalid operation: close(stop) (cannot close receive-only channel)

解析:從輸出的錯誤信息也可以知道笑撞,有方向的 channel 不可以被關(guān)閉

69岛啸、下列代碼輸出什么

func main() {
    var x = []int{2: 2, 3, 0: 1}
    fmt.Println(x)
}

答案:[1, 0, 2, 3]

解析:切片初始化特性如下:

var x = []int{2: 2, 3, 0: 1, 1}      // [1 1 2 3]
var x = []int{2: 2, 3, 0: 1, 4:4}    // [1 0 2 3 4]
var x = []int{2: 2, 3, 0: 1, 5:4}    // [1 0 2 3 0 4]

70、下面代碼輸出什么

func incr(p *int) int {
    *p++
    return *p
}
func main() {
    v := 1
    incr(&v)
    fmt.Println(v)
}

答案:2

71茴肥、下面代碼輸出什么

func main() {
    var a = []int{1, 2, 3, 4, 5}
    var r = make([]int, 0)

    for i, v := range a {
        if i == 0 {
            a = append(a, 6, 7)
        }
        r = append(r, v)
    }
    fmt.Println(r)
}

答案:[1,2,3,4,5]

解析:for range 循環(huán)時坚踩,首先會對循環(huán)對象的長度進行拷貝,循環(huán)的次數(shù)取決于拷貝的值炉爆,該拷貝值不受循環(huán)對象在循環(huán)過程中長度變化的影響

72堕虹、下面代碼有什么問題

func main() {
    var s []int
    s = append(s,1)

    var m map[string]int
    m["one"] = 1 
}

答案:編譯失敗:panic: assignment to entry in nil map

解析:切片聲明即可使用芬首,但 map 需要用 make 函數(shù) 進行初始化之后才能賦值

73赴捞、下面代碼輸出什么

func main() {
    fmt.Println("1")
    defer fmt.Println("in main")
    defer func() {
        fmt.Println("3")
    }()
    fmt.Println("2")
    defer func() {
        defer func() {
            panic("panic again and again")
        }()
        panic("panic again")
    }()
    
    panic("panic once")
}

答案:
1
2
3
in main
panic: panic once
panic: panic again
panic: panic again and again

解析:協(xié)程遇到panic時,遍歷本協(xié)程的defer鏈表郁稍,并執(zhí)行defer赦政。在執(zhí)行defer過程中,遇到recover則停止panic耀怜,返回recover處繼續(xù)往下執(zhí)行恢着。如果沒有遇到recover,遍歷完本協(xié)程的defer鏈表后财破,向stderr拋出panic信息掰派,可參考文章 關(guān)于defer坑坑洼洼的使用細節(jié)你mark了嗎

關(guān)注 公眾號「大叔說碼」 跟大叔一起打基礎(chǔ),我們下期見~

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末左痢,一起剝皮案震驚了整個濱河市靡羡,隨后出現(xiàn)的幾起案子系洛,更是在濱河造成了極大的恐慌,老刑警劉巖略步,帶你破解...
    沈念sama閱讀 211,817評論 6 492
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件描扯,死亡現(xiàn)場離奇詭異,居然都是意外死亡趟薄,警方通過查閱死者的電腦和手機绽诚,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 90,329評論 3 385
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來杭煎,“玉大人恩够,你說我怎么就攤上這事〔砻保” “怎么了玫鸟?”我有些...
    開封第一講書人閱讀 157,354評論 0 348
  • 文/不壞的土叔 我叫張陵,是天一觀的道長犀勒。 經(jīng)常有香客問我,道長妥曲,這世上最難降的妖魔是什么贾费? 我笑而不...
    開封第一講書人閱讀 56,498評論 1 284
  • 正文 為了忘掉前任,我火速辦了婚禮檐盟,結(jié)果婚禮上褂萧,老公的妹妹穿的比我還像新娘。我一直安慰自己葵萎,他們只是感情好导犹,可當(dāng)我...
    茶點故事閱讀 65,600評論 6 386
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著羡忘,像睡著了一般谎痢。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上卷雕,一...
    開封第一講書人閱讀 49,829評論 1 290
  • 那天节猿,我揣著相機與錄音,去河邊找鬼漫雕。 笑死滨嘱,一個胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的浸间。 我是一名探鬼主播太雨,決...
    沈念sama閱讀 38,979評論 3 408
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼魁蒜!你這毒婦竟也來了囊扳?” 一聲冷哼從身側(cè)響起吩翻,我...
    開封第一講書人閱讀 37,722評論 0 266
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎宪拥,沒想到半個月后仿野,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 44,189評論 1 303
  • 正文 獨居荒郊野嶺守林人離奇死亡她君,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 36,519評論 2 327
  • 正文 我和宋清朗相戀三年脚作,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片缔刹。...
    茶點故事閱讀 38,654評論 1 340
  • 序言:一個原本活蹦亂跳的男人離奇死亡球涛,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出校镐,到底是詐尸還是另有隱情亿扁,我是刑警寧澤,帶...
    沈念sama閱讀 34,329評論 4 330
  • 正文 年R本政府宣布鸟廓,位于F島的核電站从祝,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏引谜。R本人自食惡果不足惜牍陌,卻給世界環(huán)境...
    茶點故事閱讀 39,940評論 3 313
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧,春花似錦比搭、人聲如沸匣砖。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,762評論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至,卻和暖如春捡偏,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背误趴。 一陣腳步聲響...
    開封第一講書人閱讀 31,993評論 1 266
  • 我被黑心中介騙來泰國打工霹琼, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人凉当。 一個月前我還...
    沈念sama閱讀 46,382評論 2 360
  • 正文 我出身青樓枣申,卻偏偏與公主長得像,于是被迫代替她去往敵國和親看杭。 傳聞我的和親對象是個殘疾皇子忠藤,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 43,543評論 2 349

推薦閱讀更多精彩內(nèi)容