Golang面試題 練習(xí)題

整理自golang中文網(wǎng)https://studygolang.com/ 以及公眾號 golang來啦 (侵刪)

不管面試里用不用得到,萬丈高樓平地起,先得從基礎(chǔ)做起

package main
 
import (
     "fmt"
)
 
 func main() {
    defer_call()
 }

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

答案:

打印后
打印中
打印前
觸發(fā)異常

參考解析:defer 的執(zhí)行順序是后進先出。當出現(xiàn) panic 語句的時候,會先按照 defer 的后進先出的順序執(zhí)行,最后才會執(zhí)行panic。

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.Println(k,"->",*v)
    }
}

答案:

0 -> 3
0 -> 3
0 -> 3
0 -> 3

參考解析:這是新手常會犯的錯誤寫法,for range 循環(huán)的時候會創(chuàng)建每個元素的副本,而不是元素的引用,所以 m[key] = &val 取的都是變量 val 的地址,所以最后 map 中的所有元素的值都是變量 val 的地址,因為最后 val 被賦值為3,所有輸出都是3.

3.下面兩段代碼輸出什么

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

// 2.
func main() {
    s := make([]int,0)
    s = append(s,1,2,3,4)
    fmt.Println(s)
}

答案:

[0 0 0 0 0 1 2 3  ]
[1 2 3 4]

參考解析:這道題考的是使用 append 向 slice 添加元素,第一段代碼常見的錯誤是 [1 2 3],需要注意
make 分配slice內(nèi)存元素默認分配0值, slice內(nèi)存不足底層數(shù)組會重新分配

4.下面這段代碼有什么缺陷

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

答案: 返回第二個參數(shù)未命名
參考解析:
在函數(shù)有多個返回值時,只要有一個返回值有命名,其他的也必須命名。如果有多個返回值必須加上括號();如果只有一個返回值且命名也必須加上括號()。這里的第一個返回值有命名 sum,第二個沒有命名,所以錯誤。

5.new() 與 make() 的區(qū)別
參考答案:
new(T) 和 make(T,args) 是 Go 語言內(nèi)建函數(shù),用來分配內(nèi)存,但適用的類型不同。

new(T) 會為 T 類型的新值分配已置零的內(nèi)存空間,并返回地址(指針),即類型為 *T 的值。換句話說就是,返回一個指針,該指針指向新分配的、類型為 T 的零值。適用于值類型,如數(shù)組、結(jié)構(gòu)體等。

make(T,args) 返回初始化之后的 T 類型的值,這個值并不是 T 類型的零值,也不是指針 *T,是經(jīng)過初始化之后的 T 的引用。make() 只適用于 slice、map 和 channel.

6.下面這段代碼能否通過編譯,不能的話原因是什么;如果能,輸出什么

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

參考答案及解析:不能通過編譯,new([]int) 之后的 list 是一個 *[]int 類型的指針,不能對指針執(zhí)行 append 操作??梢允褂?make() 初始化之后再用。同樣的,map 和 channel 建議使用 make() 或字面量的方式初始化,不要用 new() 。

7.下面這段代碼能否通過編譯,如果可以,輸出什么?

func main() {
    s1 := []int{1, 2, 3}
    s2 := []int{4, 5}
    s1 = append(s1, s2)
    fmt.Println(s1)
}
參考答案及解析:不能通過編譯。append() 的第二個參數(shù)不能直接使用 slice,需使用 … 操作符,將一個切片追加到另一個切片上:append(s1,s2…)?;蛘咧苯痈显兀稳纾篴ppend(s1,1,2,3)。

8.下面這段代碼能否通過編譯,如果可以,輸出什么?

var(
    size := 1024
    max_size = size*2
)

func main() {
    fmt.Println(size,max_size)
}
參考答案及解析:不能通過編譯。這道題的主要知識點是變量聲明的簡短模式,形如:x := 100。但這種聲明方式有限制:
必須使用顯示初始化;
不能提供數(shù)據(jù)類型,編譯器會自動推導(dǎo);
只能在函數(shù)內(nèi)部使用簡短模式;

9.下面這段代碼能否通過編譯?不能的話,原因是什么?如果通過,輸出什么?

  func main() {
     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"}}

    if sm1 == sm2 {
        fmt.Println("sm1 == sm2")
    }
 }

參考答案及解析:編譯不通過 invalid operation: sm1 == sm2

這道題目考的是結(jié)構(gòu)體的比較,有幾個需要注意的地方:

1>. 結(jié)構(gòu)體只能比較是否相等,但是不能比較大小。

2>. 相同類型的結(jié)構(gòu)體才能夠進行比較,結(jié)構(gòu)體是否相同不但與屬性類型有關(guān),還與屬性順序相關(guān),sn3 與 sn1 就是不同的結(jié)構(gòu)體;

    sn3:= struct {
        name string
        age  int4    }{age:11,name:"qq"}

3>. 如果 struct 的所有成員都可以比較,則該 struct 就可以通過 == 或 != 進行比較是否相等,比較時逐個項進行比較,如果每一項都相等,則兩個結(jié)構(gòu)體才相等,否則不相等;

那什么是可比較的呢,常見的有 bool、數(shù)值型、字符、指針、數(shù)組等,像切片、map、函數(shù)等是不能比較的。 具體可以參考 Go 說明文檔。http://docs.studygolang.com/ref/spec#Comparison_operators

10.通過指針變量 p 訪問其成員變量 name,有哪幾種方式?
A.p.name
B.(&p).name
C.(*p).name
D.p->name
參考答案及解析:A C

11.下面這段代碼能否通過編譯?如果通過,輸出什么?

 package main
 
 import "fmt"
 
 type MyInt1 int
 type MyInt2 = int
 
func main() {
    var i int =0
    var i1 MyInt1 = i 
    var i2 MyInt2 = i
    fmt.Println(i1,i2)
}

參考答案及解析:編譯不通過,cannot use i (type int) as type MyInt1 in assignment。

這道題考的是類型別名與類型定義的區(qū)別。

第 5 行代碼是基于類型 int 創(chuàng)建了新類型 MyInt1,第 6 行代碼是創(chuàng)建了 int 的類型別名 MyInt2,注意類型別名的定義時 = 。所以,第 10 行代碼相當于是將 int 類型的變量賦值給 MyInt1 類型的變量,Go 是強類型語言,編譯當然不通過;而 MyInt2 只是 int 的別名,本質(zhì)上還是 int,可以賦值。

第 10 行代碼的賦值可以使用強制類型轉(zhuǎn)化 var i1 MyInt1 = MyInt1(i).

12.關(guān)于字符串連接,下面語法正確的是?

A. str := 'abc' + '123'
B. str := "abc" + "123"
C. str := '123' + "abc"
D. fmt.Sprintf("abc%d", 123)

參考答案:B D

知識點:字符串連接。除了以上兩種連接方式,還有 strings.Join()、buffer.WriteString()等

13.下面這段代碼能否編譯通過?如果可以,輸出什么?

package main

import "fmt"

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

func main()  {
    fmt.Println(x,y,z,k,p)
}

參考答案及解析:編譯通過,輸出:0 2 zz zz 5。知識點:iota 的使用。給大家貼篇文章,講的很詳細
https://www.cnblogs.com/zsy/p/5370052.html

14.下面賦值正確的是()

A. var x = nil
B. var x interface{} = nil
C. var x string = nil
D. var x error = nil

B D

參考答案及解析:BD。知識點:nil 值。nil 只能賦值給指針、chan、func、interface、map 或 slice 類型的變量。強調(diào)下 D 選項的 error 類型,它是一種內(nèi)置接口類型,看下方貼出的源碼就知道,所以 D 是對的。

type error interface {
    Error() string
}

15.關(guān)于init函數(shù),下面說法正確的是()

A. 一個包中,可以包含多個 init 函數(shù);
B. 程序編譯時,先執(zhí)行依賴包的 init 函數(shù),再執(zhí)行 main 包內(nèi)的 init 函數(shù);
C. main 包中,不能有 init 函數(shù);
D. init 函數(shù)可以被其他函數(shù)調(diào)用;
參考答案及解析:AB
關(guān)于 init() 函數(shù)有幾個需要注意的地方:

1> init() 函數(shù)是用于程序執(zhí)行前做包的初始化的函數(shù),比如初始化包里的變量等;
2>一個包可以出線多個 init() 函數(shù),一個源文件也可以包含多個 init() 函數(shù);
3> 同一個包中多個 init() 函數(shù)的執(zhí)行順序沒有明確定義,但是不同包的init函數(shù)是根據(jù)包導(dǎo)入的依賴關(guān)系決定的(看下圖);


image.png

init() 函數(shù)在代碼中不能被顯示調(diào)用、不能被引用(賦值給函數(shù)變量),否則出現(xiàn)編譯錯誤;
一個包被引用多次,如 A import B,C import B,A import C,B 被引用多次,但 B 包只會初始化一次;
引入包,不可出現(xiàn)死循壞。即 A import B,B import A,這種情況編譯失?。?/p>

16.下面這段代碼輸出什么以及原因?

 func hello() []string {  
     return nil
 }
 
 func main() {  
     h := hello
     if h == nil {
         fmt.Println("nil")
     } else {
        fmt.Println("not nil")
     }
}

A. nil
B. not nil
C. compilation error

答案及解析:B。這道題目里面,是將 hello() 賦值給變量 h,而不是函數(shù)的返回值,所以輸出 not nil。

17.下面這段代碼能否編譯通過?如果可以,輸出什么?

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

參考答案及解析:編譯失敗??键c:類型選擇,類型選擇的語法形如:i.(type),其中 i 是接口,type 是固定關(guān)鍵字,需要注意的是,只有接口類型才可以使用類型選擇。看下關(guān)于接口的文章。

18.關(guān)于channel,下面語法正確的是()

A. var ch chan int
B. ch := make(chan int)
C. <- ch
D. ch <-

參考答案及解析:ABC。A、B都是聲明 channel;C 讀取 channel;寫 channel 是必須帶上值,所以 D 錯誤。

19.下面這段代碼輸出什么?
A.0
B.1
C.Compilation error

type person struct {  
    name string
}

func main() {  
    var m map[person]int
    p := person{"mike"}
    fmt.Println(m[p])
}

參考答案及解析:A。打印一個 map 中不存在的值時,返回元素類型的零值。這個例子中,m 的類型是 map[person]int,因為 m 中不存在 p,所以打印 int 類型的零值,即 0。

20.下面這段代碼輸出什么?

A.18
B.5
C.Compilation error

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

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

參考答案及解析:A 。...語法糖把切片傳入只要不發(fā)生擴容就會影響到原始切片

21.下面這段代碼輸出什么?

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

A.13.1
B.13
C.compilation error

參考答案及解析:C。a 的類型是 int,b 的類型是 float,兩個不同類型的數(shù)值不能相加,編譯報錯。

22.下面這段代碼輸出什么?

package main

import (  
    "fmt"
)

func main() {  
    a := [5]int{1, 2, 3, 4, 5}
    t := a[3:4:4]
    fmt.Println(t[0])
}

A.3
B.4
C.compilation error
參考答案及解析:B。
知識點:操作符 [i,j]。基于數(shù)組(切片)可以使用操作符 [i,j] 創(chuàng)建新的切片,從索引 i,到索引 j 結(jié)束,截取已有數(shù)組(切片)的任意部分,返回新的切片,新切片的值包含原數(shù)組(切片)的 i 索引的值,但是不包含 j 索引的值。i、j 都是可選的,i 如果省略,默認是 0,j 如果省略,默認是原數(shù)組(切片)的長度。i、j 都不能超過這個長度值。

假如底層數(shù)組的大小為 k,截取之后獲得的切片的長度和容量的計算方法:長度:j-i,容量:k-i。

截取操作符還可以有第三個參數(shù),形如 [i,j,k],第三個參數(shù) k 用來限制新切片的容量,但不能超過原數(shù)組(切片)的底層數(shù)組大小。截取獲得的切片的長度和容量分別是:j-i、k-i。

所以例子中,切片 t 為 [4],長度和容量都是 1。

詳細的知識點可以看下關(guān)于切片的文章。

23.下面這段代碼輸出什么?

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。Go 中的數(shù)組是值類型,可比較,另外一方面,數(shù)組的長度也是數(shù)組類型的組成部分,所以 a 和 b 是不同的類型,是不能比較的,所以編譯錯誤。

24.關(guān)于 cap() 函數(shù)的適用類型,下面說法正確的是()
A. array
B. slice
C. map
D. channel

A B D
知識點:cap(),cap() 函數(shù)不適用 map。

25.下面這段代碼輸出什么?

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

A. nil
B. not nil
C. compilation error

參考答案及解析:A。當且僅當接口的動態(tài)值和動態(tài)類型都為 nil 時,接口類型值才為 nil。

關(guān)于接口詳細的介紹可以看下之前的文章

26.下面這段代碼輸出什么?

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

A. runtime panic
B. 0
C. compilation error
參考答案及解析:B。刪除 map 不存在的鍵值對時,不會報錯,相當于沒有任何作用;獲取不存在的減值對時,返回值類型對應(yīng)的零值,所以返回 0。

27.下面屬于關(guān)鍵字的是()

A.func
B.struct
C.class
D.defer

參考答案及解析:ABD。知識點:Go 語言的關(guān)鍵字。Go 語言有 25 個關(guān)鍵字,看下圖:


image.png

28.下面這段代碼輸出什么?

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

A. -5 +5
B. +5 +5
C. 0 0

參考答案及解析:A。%d表示輸出十進制數(shù)字,+表示輸出數(shù)值的符號。這里不表示取反。

29.下面這段代碼輸出什么?

type People struct{}

func (p *People) ShowA() {
    fmt.Println("showA")
    p.ShowB()
}
func (p *People) ShowB() {
    fmt.Println("showB")
}

type Teacher struct {
    People
}

func (t *Teacher) ShowB() {
    fmt.Println("teacher showB")
}

func main() {
    t := Teacher{}
    t.ShowB()
}

參考答案及解析:teacher showB。知識點:結(jié)構(gòu)體嵌套。在嵌套結(jié)構(gòu)體中,People 稱為內(nèi)部類型,Teacher 稱為外部類型;通過嵌套,內(nèi)部類型的屬性、方法,可以為外部類型所有,就好像是外部類型自己的一樣。此外,外部類型還可以定義自己的屬性和方法,甚至可以定義與內(nèi)部相同的方法,這樣內(nèi)部類型的方法就會被“屏蔽”。這個例子中的 ShowB() 就是同名方法。

30.定義一個包內(nèi)全局字符串變量,下面語法正確的是()
A. var str string
B. str := ""
C. str = ""
D. var str = ""

參考答案及解析:AD。B 只支持局部變量聲明;C 是賦值,str 必須在這之前已經(jīng)聲明;

31.下面這段代碼輸出什么?

type People struct{}

func (p *People) ShowA() {
    fmt.Println("showA")
    p.ShowB()
}
func (p *People) ShowB() {
    fmt.Println("showB")
}

type Teacher struct {
    People
}

func (t *Teacher) ShowB() {
    fmt.Println("teacher showB")
}

func main() {
    t := Teacher{}
    t.ShowA()
}

參考答案及解析:

showA
showB
知識點:結(jié)構(gòu)體嵌套。這道題可以結(jié)合第 12 天的第三題一起看,Teacher 沒有自己 ShowA(),所以調(diào)用內(nèi)部類型 People 的同名方法,需要注意的是第 5 行代碼調(diào)用的是 People 自己的 ShowB 方法。

32.下面這段代碼輸出什么?

func hello(i int) {  
    fmt.Println(i)
}
func main() {  
    i := 5
    defer hello(i)
    i = i + 10
}

參考答案及解析:5。這個例子中,hello() 函數(shù)的參數(shù)在執(zhí)行 defer 語句的時候會保存一份副本,在實際調(diào)用 hello() 函數(shù)時用,所以是 5.

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

A. hello
B. xello
C. compilation error

C

34.下面代碼輸出什么?

func incr(p *int) int {
    *p++
    return *p
}

func main() {
    p :=1
    incr(&p)
    fmt.Println(p)
}

A. 1
B. 2
C. 3

B

35.對 add() 函數(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}…)
A B D

36.下面代碼下劃線處可以填入哪個選項?

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

A. s1
B. s2
C. s1、s2 都可以

C

37.下面這段代碼輸出什么?

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

A. A
B. 65
C. compilation error

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

38.下面這段代碼輸出什么?

type A interface {
    ShowA() int
}

type B interface {
    ShowB() int
}

type Work struct {
    i int
}

func (w Work) ShowA() int {
    return w.i + 10
}

func (w Work) ShowB() int {
    return w.i + 20
}

func main() {
    c := Work{3}
    var a A = c
    var b B = c
    fmt.Println(a.ShowA())
    fmt.Println(b.ShowB())
}

13 23
參考答案及解析:13 23。知識點:接口。一種類型實現(xiàn)多個接口,結(jié)構(gòu)體 Work 分別實現(xiàn)了接口 A、B,所以接口變量 a、b 調(diào)用各自的方法 ShowA() 和 ShowB(),輸出 13、23。

39.切片 a、b、c 的長度和容量分別是多少?

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

參考答案及解析:a、b、c 的長度和容量分別是 0 3、2 3、1 2。知識點:數(shù)組或切片的截取操作。截取操作有帶 2 個或者 3 個參數(shù),形如:[i:j] 和 [i:j:k],假設(shè)截取對象的底層數(shù)組長度為 l。在操作符 [i:j] 中,如果 i 省略,默認 0,如果 j 省略,默認底層數(shù)組的長度,截取得到的切片長度和容量計算方法是 j-i、l-i。操作符 [i:j:k],k 主要是用來限制切片的容量,但是不能大于數(shù)組的長度 l,截取得到的切片長度和容量計算方法是 j-i、k-i

40.下面代碼中 A B 兩處應(yīng)該怎么修改才能順利編譯?

func main() {
    var m map[string]int        //A
    m["a"] = 1
    if v := m["b"]; v != nil {  //B
        fmt.Println(v)
    }
}

m := make(map[stringint])
v, ok := m["b"]; ok
在 A 處只聲明了map m ,并沒有分配內(nèi)存空間,不能直接賦值,需要使用 make(),都提倡使用 make() 或者字面量的方式直接初始化 map。

B 處,v,k := m["b"] 當 key 為 b 的元素不存在的時候,v 會返回值類型對應(yīng)的零值,k 返回 false。

  1. 下面代碼輸出什么?
type A interface {
    ShowA() int
}

type B interface {
    ShowB() int
}

type Work struct {
    i int
}

func (w Work) ShowA() int {
    return w.i + 10
}

func (w Work) ShowB() int {
    return w.i + 20
}

func main() {
    c := Work{3}
    var a A = c
    var b B = c
    fmt.Println(a.ShowB())
    fmt.Println(b.ShowA())
}

A. 23 13
B. compilation error

參考答案及解析:B。知識點:接口的靜態(tài)類型。a、b 具有相同的動態(tài)類型和動態(tài)值,分別是結(jié)構(gòu)體 work 和 {3};a 的靜態(tài)類型是 A,b 的靜態(tài)類型是 B,接口 A 不包括方法 ShowB(),接口 B 也不包括方法 ShowA(),編譯報錯。看下編譯錯誤:

a.ShowB undefined (type A has no field or method ShowB)
b.ShowA undefined (type B has no field or method ShowA)

42.下面代碼中,x 已聲明,y 沒有聲明,判斷每條語句的對錯。

 1. x, _ := f()
 2. x, _ = f()
 3. x, y := f()
 4. x, y = f()

參考答案及解析:錯、對、對、錯。知識點:變量的聲明。1.錯,x 已經(jīng)聲明,不能使用 :=;2.對;3.對,當多值賦值時,:= 左邊的變量無論聲明與否都可以;4.錯,y 沒有聲明。

43.下面代碼輸出什么?

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

A. 1 1
B. 0 1
C. 1 0
D. 0 0

B

44.下面代碼輸出什么?

type A interface {
    ShowA() int
}

type B interface {
    ShowB() int
}

type Work struct {
    i int
}

func (w Work) ShowA() int {
    return w.i + 10
}

func (w Work) ShowB() int {
    return w.i + 20
}

func main() {
    var a A = Work{3}
    s := a.(Work)
    fmt.Println(s.ShowA())
    fmt.Println(s.ShowB())
}

A. 13 23
B. compilation error

A 類型斷言可以用來獲取接口的底層值, 通常的語法:i.(Type), 其中i是接口,其實i是接口,Type是類型或接口。編譯時會自動檢測i的動態(tài)類型與type是否一致

45.f1()、f2()、f3() 函數(shù)分別返回什么?

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
}

1 5 1

46.下面的題目輸出什么?

type Person struct {
    age int
}

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

    // 1. 
    defer fmt.Println(person.age)

    // 2.
    defer func(p *Person) {
        fmt.Println(p.age)
    }(person)  

    // 3.
    defer func() {
        fmt.Println(person.age)
    }()

    person.age = 29
}

29 29 28

47.下面代碼輸出什么?

func f() {
    defer fmt.Println("D")
    fmt.Println("F")
}

func main() {
    f()
    fmt.Println("M")
}

A. F M D
B. D F M
C. F D M

C

48.下面代碼輸出什么

type Person struct {
    age int
}

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

    // 1.
    defer fmt.Println(person.age)

    // 2.
    defer func(p *Person) {
        fmt.Println(p.age)
    }(person)

    // 3.
    defer func() {
        fmt.Println(person.age)
    }()

    person = &Person{29}
}

29 28 28

49.下面的兩個切片聲明中有什么區(qū)別?哪個更可取?

A. var a []int
B. a := []int{}

.參考答案及解析:A 聲明的是 nil 切片;B 聲明的是長度和容量都為 0 的空切片。第一種切片聲明不會分配內(nèi)存,優(yōu)先選擇

50.A、B、C、D 哪些選項有語法錯誤?

type S struct {
}

func f(x interface{}) {
}

func g(x *interface{}) {
}

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

B D

51.下面 A、B 兩處應(yīng)該填入什么代碼,才能確保順利打印出結(jié)果?

type S struct {
    m string
}

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

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

A. &S{"foo"}
B. *f() 或者 f()

f() 函數(shù)返回參數(shù)是指針類型,所以可以用 & 取結(jié)構(gòu)體的指針;B 處,如果填 *f(),則 p 是 S 類型;如果填 f(),則 p 是 *S 類型,不過都可以使用 p.m 取得結(jié)構(gòu)體的成員

52.下面的代碼各有幾處語法問題,各是什么?

package main

import (
    "fmt"
)
func main() {
    var x string = nil

    if x == nil {
        x = "default"
    }
    fmt.Println(x)
}

string 不能是nil 不能和nil 比較

53.return 之后的 defer 語句會執(zhí)行嗎,下面這段代碼輸出什么?

var a bool = true
func main() {
    defer func(){
        fmt.Println("1")
    }()
    if a == true {
        fmt.Println("2")
        return
    }
    defer func(){
        fmt.Println("3")
    }()
}

參考答案及解析:2 1。defer 關(guān)鍵字后面的函數(shù)或者方法想要執(zhí)行必須先注冊,return 之后的 defer 是不能注冊的, 也就不能執(zhí)行后面的函數(shù)或方法。

54.下面這段代碼輸出什么?為什么?

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

我們知道,golang 中切片底層的數(shù)據(jù)結(jié)構(gòu)是數(shù)組。當使用 s1[1:] 獲得切片 s2,和 s1 共享同一個底層數(shù)組,這會導(dǎo)致 s2[1] = 4 語句影響 s1。

而 append 操作會導(dǎo)致底層數(shù)組擴容,生成新的數(shù)組,因此追加數(shù)據(jù)后的 s2 不會影響 s1。

但是為什么對 s2 賦值后影響的卻是 s1 的第三個元素呢?這是因為切片 s2 是從數(shù)組的第二個元素開始,s2 索引為 1 的元素對應(yīng)的是 s1 索引為 2 的元素。

image

55.下面選項正確的是?

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

A. 1 2
B. compilation error

A

56.下面這段代碼輸出什么?

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

57.下面這段代碼輸出什么?

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
}

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

參考答案及解析:

10 1 2 3
20 0 2 2
2 0 2 2
1 1 3 4
程序執(zhí)行到 main() 函數(shù)三行代碼的時候,會先執(zhí)行 calc() 函數(shù)的 b 參數(shù),即:calc("10",a,b),輸出:10 1 2 3,得到值 3,因為
defer 定義的函數(shù)是延遲函數(shù),故 calc("1",1,3) 會被延遲執(zhí)行;

程序執(zhí)行到第五行的時候,同樣先執(zhí)行 calc("20",a,b) 輸出:20 0 2 2 得到值 2,同樣將 calc("2",0,2) 延遲執(zhí)行;

程序執(zhí)行到末尾的時候,按照棧先進后出的方式依次執(zhí)行:calc("2",0,2),calc("1",1,3),則就依次輸出:2 0 2 2,1 1 3 4。

58.下面這段代碼輸出什么?為什么?

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

func main() {
    var i int = 1
    i.PrintInt()
}

A. 1
B. compilation error

參考答案及解析:B?;陬愋蛣?chuàng)建的方法必須定義在同一個包內(nèi),上面的代碼基于 int 類型創(chuàng)建了 PrintInt() 方法,由于 int 類型和方法 PrintInt() 定義在不同的包內(nèi),所以編譯出錯。

59.下面這段代碼輸出什么?為什么?

type People interface {
    Speak(string) string
}

type Student struct{}

func (stu *Student) Speak(think string) (talk string) {
    if think == "speak" {
        talk = "speak"
    } else {
        talk = "hi"
    }
    return
}

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

A. speak
B. compilation error

參考答案及解析:B。編譯錯誤 Student does not implement People (Speak method has pointer receiver),值類型 Student 沒有實現(xiàn)接口的 Speak() 方法,而是指針類型 *Student 實現(xiàn)該方法。

60.下面這段代碼輸出什么?

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 0 0 0
知識點:iota 的用法。

iota 是 golang 語言的常量計數(shù)器,只能在常量的表達式中使用。

iota 在 const 關(guān)鍵字出現(xiàn)時將被重置為0,const中每新增一行常量聲明將使 iota 計數(shù)一次。

推薦閱讀:
https://studygolang.com/articles/2192

61.下面這段代碼輸出什么?為什么?

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
s is not nil

參考答案及解析:s is nil 和 p is not nil。這道題會不會有點詫異,我們分配給變量 p 的值明明是 nil,然而 p 卻不是 nil。記住一點,當且僅當動態(tài)值和動態(tài)類型都為 nil 時,接口類型值才為 nil。上面的代碼,給變量 p 賦值之后,p 的動態(tài)值是 nil,但是動態(tài)類型卻是 *Student,是一個 nil 指針,所以相等條件不成立。

62.下面這段代碼輸出什么?

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 的用法、類型的 String() 方法。

根據(jù) iota 的用法推斷出 South 的值是 3;另外,如果類型定義了 String() 方法,當使用 fmt.Printf()、fmt.Print() 和 fmt.Println() 會自動使用 String() 方法,實現(xiàn)字符串的打印。

63.下面代碼輸出什么?

type Math struct {
    x, y int
}

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

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

A. 4
B. compilation error

參考答案及解析:B,編譯報錯 cannot assign to struct field m["foo"].x in map。錯誤原因:對于類似 X = Y的賦值操作,必須知道 X 的地址,才能夠?qū)?Y 的值賦給 X,但 go 中的 map 的 value 本身是不可尋址的。

有兩個解決辦法:

使用臨時變量

type Math struct {
    x, y int
}

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

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

修改數(shù)據(jù)結(jié)構(gòu)

type Math struct {
    x, y int
}

var m = map[string]*Math{
    "foo": &Math{2, 3},
}

func main() {
    m["foo"].x = 4
    fmt.Println(m["foo"].x)
    fmt.Printf("%#v", m["foo"])   // %#v 格式化輸出詳細信息
}

64.下面的代碼有什么問題?

func main() {
    fmt.Println([...]int{1} == [2]int{1})
    fmt.Println([]int{1} == []int{1})
}

參考答案及解析:有兩處錯誤

go 中不同類型是不能比較的,而數(shù)組長度是數(shù)組類型的一部分,所以 […]int{1} 和 [2]int{1} 是兩種不同的類型,不能比較;
切片是不能比較的;

65.下面這段代碼輸出什么?如果編譯錯誤的話,為什么?

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

A. 5 5
B. runtime error

參考答案及解析:B。知識點:變量作用域。問題出在操作符:=,對于使用:=定義的變量,如果新變量與同名已定義的變量不在同一個作用域中,那么 Go 會新定義這個變量。對于本例來說,main() 函數(shù)里的 p 是新定義的變量,會遮住全局變量 p,導(dǎo)致執(zhí)行到bar()時程序,全局變量 p 依然還是 nil,程序隨即 Crash。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

  • 這是16年5月份編輯的一份比較雜亂適合自己觀看的學(xué)習(xí)記錄文檔,今天18年5月份再次想寫文章,發(fā)現(xiàn)簡書還為我保存起的...
    Jenaral閱讀 3,186評論 2 9
  • 選擇題部分 1.(),只有在發(fā)生短路事故時或者在負荷電流較大時,變流器中才會有足夠的二次電流作為繼電保護跳閘之用。...
    skystarwuwei閱讀 14,436評論 0 7
  • 1. 關(guān)于診斷X線機準直器的作用,錯誤的是()。 (6.0 分) A. 顯示照射野 B. 顯示中心線 C. 屏蔽多...
    我們村我最帥閱讀 11,504評論 0 5
  • 1. 下列敘述錯誤的是()。 (2.0 分) A. 質(zhì)量管理包括QA和QC一切活動的全部過程 B. 影像質(zhì)量是指對...
    我們村我最帥閱讀 4,413評論 0 8
  • 在C語言中,五種基本數(shù)據(jù)類型存儲空間長度的排列順序是: A)char B)char=int<=float C)ch...
    夏天再來閱讀 4,092評論 0 2

友情鏈接更多精彩內(nèi)容