整理自golang中文網(wǎng)https://studygolang.com/ 以及公眾號(hào) golang來(lái)啦 (侵刪)
不管面試?yán)镉貌挥玫玫窖艟啵f(wàn)丈高樓平地起,先得從基礎(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í)行順序是后進(jìn)先出千诬。當(dāng)出現(xiàn) panic 語(yǔ)句的時(shí)候滔吠,會(huì)先按照 defer 的后進(jìn)先出的順序執(zhí)行民褂,最后才會(huì)執(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
參考解析:這是新手常會(huì)犯的錯(cuò)誤寫法柳弄,for range 循環(huán)的時(shí)候會(huì)創(chuàng)建每個(gè)元素的副本舶胀,而不是元素的引用,所以 m[key] = &val 取的都是變量 val 的地址碧注,所以最后 map 中的所有元素的值都是變量 val 的地址嚣伐,因?yàn)樽詈?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 添加元素萍丐,第一段代碼常見(jiàn)的錯(cuò)誤是 [1 2 3]轩端,需要注意
make 分配slice內(nèi)存元素默認(rèn)分配0值, slice內(nèi)存不足底層數(shù)組會(huì)重新分配
4.下面這段代碼有什么缺陷
func funcMui(x,y int)(sum int,error){
return x+y,nil
}
答案: 返回第二個(gè)參數(shù)未命名
參考解析:
在函數(shù)有多個(gè)返回值時(shí)逝变,只要有一個(gè)返回值有命名基茵,其他的也必須命名。如果有多個(gè)返回值必須加上括號(hào)()壳影;如果只有一個(gè)返回值且命名也必須加上括號(hào)()拱层。這里的第一個(gè)返回值有命名 sum,第二個(gè)沒(méi)有命名态贤,所以錯(cuò)誤舱呻。
5.new() 與 make() 的區(qū)別
參考答案:
new(T) 和 make(T,args) 是 Go 語(yǔ)言內(nèi)建函數(shù),用來(lái)分配內(nèi)存,但適用的類型不同箱吕。
new(T) 會(huì)為 T 類型的新值分配已置零的內(nèi)存空間芥驳,并返回地址(指針),即類型為 *T 的值茬高。換句話說(shuō)就是兆旬,返回一個(gè)指針,該指針指向新分配的怎栽、類型為 T 的零值丽猬。適用于值類型,如數(shù)組熏瞄、結(jié)構(gòu)體等脚祟。
make(T,args) 返回初始化之后的 T 類型的值,這個(gè)值并不是 T 類型的零值强饮,也不是指針 *T由桌,是經(jīng)過(guò)初始化之后的 T 的引用。make() 只適用于 slice邮丰、map 和 channel.
6.下面這段代碼能否通過(guò)編譯行您,不能的話原因是什么;如果能剪廉,輸出什么
func main() {
list := new([]int)
list = append(list, 1)
fmt.Println(list)
}
參考答案及解析:不能通過(guò)編譯娃循,new([]int) 之后的 list 是一個(gè) *[]int 類型的指針,不能對(duì)指針執(zhí)行 append 操作斗蒋“聘可以使用 make() 初始化之后再用。同樣的吹泡,map 和 channel 建議使用 make() 或字面量的方式初始化骤星,不要用 new() 。
7.下面這段代碼能否通過(guò)編譯爆哑,如果可以,輸出什么舆吮?
func main() {
s1 := []int{1, 2, 3}
s2 := []int{4, 5}
s1 = append(s1, s2)
fmt.Println(s1)
}
參考答案及解析:不能通過(guò)編譯揭朝。append() 的第二個(gè)參數(shù)不能直接使用 slice,需使用 … 操作符色冀,將一個(gè)切片追加到另一個(gè)切片上:append(s1,s2…)潭袱。或者直接跟上元素锋恬,形如:append(s1,1,2,3)屯换。
8.下面這段代碼能否通過(guò)編譯,如果可以,輸出什么彤悔?
var(
size := 1024
max_size = size*2
)
func main() {
fmt.Println(size,max_size)
}
參考答案及解析:不能通過(guò)編譯嘉抓。這道題的主要知識(shí)點(diǎn)是變量聲明的簡(jiǎn)短模式,形如:x := 100晕窑。但這種聲明方式有限制:
必須使用顯示初始化抑片;
不能提供數(shù)據(jù)類型,編譯器會(huì)自動(dòng)推導(dǎo)杨赤;
只能在函數(shù)內(nèi)部使用簡(jiǎn)短模式敞斋;
9.下面這段代碼能否通過(guò)編譯?不能的話疾牲,原因是什么植捎?如果通過(guò),輸出什么阳柔?
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")
}
}
參考答案及解析:編譯不通過(guò) invalid operation: sm1 == sm2
這道題目考的是結(jié)構(gòu)體的比較焰枢,有幾個(gè)需要注意的地方:
1>. 結(jié)構(gòu)體只能比較是否相等,但是不能比較大小盔沫。
2>. 相同類型的結(jié)構(gòu)體才能夠進(jìn)行比較医咨,結(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 就可以通過(guò) == 或 != 進(jìn)行比較是否相等谴忧,比較時(shí)逐個(gè)項(xiàng)進(jìn)行比較很泊,如果每一項(xiàng)都相等,則兩個(gè)結(jié)構(gòu)體才相等沾谓,否則不相等委造;
那什么是可比較的呢,常見(jiàn)的有 bool均驶、數(shù)值型昏兆、字符、指針妇穴、數(shù)組等爬虱,像切片、map腾它、函數(shù)等是不能比較的跑筝。 具體可以參考 Go 說(shuō)明文檔。http://docs.studygolang.com/ref/spec#Comparison_operators
10.通過(guò)指針變量 p 訪問(wèn)其成員變量 name瞒滴,有哪幾種方式曲梗?
A.p.name
B.(&p).name
C.(*p).name
D.p->name
參考答案及解析:A C
11.下面這段代碼能否通過(guò)編譯?如果通過(guò),輸出什么虏两?
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)
}
參考答案及解析:編譯不通過(guò)愧旦,cannot use i (type int) as type MyInt1 in assignment。
這道題考的是類型別名與類型定義的區(qū)別碘举。
第 5 行代碼是基于類型 int 創(chuàng)建了新類型 MyInt1忘瓦,第 6 行代碼是創(chuàng)建了 int 的類型別名 MyInt2陶衅,注意類型別名的定義時(shí) = 么介。所以豌骏,第 10 行代碼相當(dāng)于是將 int 類型的變量賦值給 MyInt1 類型的變量方面,Go 是強(qiáng)類型語(yǔ)言服猪,編譯當(dāng)然不通過(guò)巷送;而 MyInt2 只是 int 的別名醉拓,本質(zhì)上還是 int圈盔,可以賦值售滤。
第 10 行代碼的賦值可以使用強(qiáng)制類型轉(zhuǎn)化 var i1 MyInt1 = MyInt1(i).
12.關(guān)于字符串連接罚拟,下面語(yǔ)法正確的是?
A. str := 'abc' + '123'
B. str := "abc" + "123"
C. str := '123' + "abc"
D. fmt.Sprintf("abc%d", 123)
參考答案:B D
知識(shí)點(diǎn):字符串連接完箩。除了以上兩種連接方式赐俗,還有 strings.Join()、buffer.WriteString()等
13.下面這段代碼能否編譯通過(guò)弊知?如果可以阻逮,輸出什么?
package main
import "fmt"
const (
x = iota
_
y
z = "zz"
k
p = iota
)
func main() {
fmt.Println(x,y,z,k,p)
}
參考答案及解析:編譯通過(guò)秩彤,輸出:0 2 zz zz 5叔扼。知識(shí)點(diǎn):iota 的使用。給大家貼篇文章漫雷,講的很詳細(xì)
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瓜富。知識(shí)點(diǎn):nil 值。nil 只能賦值給指針降盹、chan与柑、func、interface蓄坏、map 或 slice 類型的變量仅胞。強(qiáng)調(diào)下 D 選項(xiàng)的 error 類型,它是一種內(nèi)置接口類型剑辫,看下方貼出的源碼就知道,所以 D 是對(duì)的渠欺。
type error interface {
Error() string
}
15.關(guān)于init函數(shù)妹蔽,下面說(shuō)法正確的是()
A. 一個(gè)包中,可以包含多個(gè) init 函數(shù);
B. 程序編譯時(shí)胳岂,先執(zhí)行依賴包的 init 函數(shù)编整,再執(zhí)行 main 包內(nèi)的 init 函數(shù);
C. main 包中乳丰,不能有 init 函數(shù)掌测;
D. init 函數(shù)可以被其他函數(shù)調(diào)用;
參考答案及解析:AB
關(guān)于 init() 函數(shù)有幾個(gè)需要注意的地方:
1> init() 函數(shù)是用于程序執(zhí)行前做包的初始化的函數(shù)产园,比如初始化包里的變量等;
2>一個(gè)包可以出線多個(gè) init() 函數(shù),一個(gè)源文件也可以包含多個(gè) init() 函數(shù)汞斧;
3> 同一個(gè)包中多個(gè) init() 函數(shù)的執(zhí)行順序沒(méi)有明確定義,但是不同包的init函數(shù)是根據(jù)包導(dǎo)入的依賴關(guān)系決定的(看下圖);
init() 函數(shù)在代碼中不能被顯示調(diào)用什燕、不能被引用(賦值給函數(shù)變量)粘勒,否則出現(xiàn)編譯錯(cuò)誤;
一個(gè)包被引用多次,如 A import B,C import B,A import C屎即,B 被引用多次庙睡,但 B 包只會(huì)初始化一次;
引入包技俐,不可出現(xiàn)死循壞乘陪。即 A import B,B import A,這種情況編譯失數窭蕖啡邑;
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.下面這段代碼能否編譯通過(guò)?如果可以仪缸,輸出什么贵涵?
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")
}
}
參考答案及解析:編譯失敗∏』考點(diǎn):類型選擇宾茂,類型選擇的語(yǔ)法形如:i.(type),其中 i 是接口拴还,type 是固定關(guān)鍵字跨晴,需要注意的是,只有接口類型才可以使用類型選擇片林《伺瑁看下關(guān)于接口的文章怀骤。
18.關(guān)于channel,下面語(yǔ)法正確的是()
A. var ch chan int
B. ch := make(chan int)
C. <- ch
D. ch <-
參考答案及解析:ABC焕妙。A蒋伦、B都是聲明 channel;C 讀取 channel焚鹊;寫 channel 是必須帶上值痕届,所以 D 錯(cuò)誤。
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研叫。打印一個(gè) map 中不存在的值時(shí),返回元素類型的零值阻塑。這個(gè)例子中蓝撇,m 的類型是 map[person]int,因?yàn)?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 独柑。...語(yǔ)法糖把切片傳入只要不發(fā)生擴(kuò)容就會(huì)影響到原始切片
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,兩個(gè)不同類型的數(shù)值不能相加曲稼,編譯報(bào)錯(cuò)索绪。
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贫悄。
知識(shí)點(diǎn):操作符 [i,j]瑞驱。基于數(shù)組(切片)可以使用操作符 [i,j] 創(chuàng)建新的切片窄坦,從索引 i唤反,到索引 j 結(jié)束,截取已有數(shù)組(切片)的任意部分鸭津,返回新的切片彤侍,新切片的值包含原數(shù)組(切片)的 i 索引的值,但是不包含 j 索引的值逆趋。i盏阶、j 都是可選的,i 如果省略闻书,默認(rèn)是 0般哼,j 如果省略吴汪,默認(rèn)是原數(shù)組(切片)的長(zhǎng)度。i蒸眠、j 都不能超過(guò)這個(gè)長(zhǎng)度值。
假如底層數(shù)組的大小為 k杆融,截取之后獲得的切片的長(zhǎng)度和容量的計(jì)算方法:長(zhǎng)度:j-i楞卡,容量:k-i。
截取操作符還可以有第三個(gè)參數(shù)脾歇,形如 [i,j,k]蒋腮,第三個(gè)參數(shù) k 用來(lái)限制新切片的容量,但不能超過(guò)原數(shù)組(切片)的底層數(shù)組大小藕各。截取獲得的切片的長(zhǎng)度和容量分別是:j-i池摧、k-i。
所以例子中激况,切片 t 為 [4]作彤,長(zhǎng)度和容量都是 1。
詳細(xì)的知識(shí)點(diǎn)可以看下關(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ù)組的長(zhǎng)度也是數(shù)組類型的組成部分洛波,所以 a 和 b 是不同的類型胰舆,是不能比較的,所以編譯錯(cuò)誤蹬挤。
24.關(guān)于 cap() 函數(shù)的適用類型缚窿,下面說(shuō)法正確的是()
A. array
B. slice
C. map
D. channel
A B D
知識(shí)點(diǎn):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。當(dāng)且僅當(dāng)接口的動(dòng)態(tài)值和動(dòng)態(tài)類型都為 nil 時(shí)蓝翰,接口類型值才為 nil光绕。
關(guān)于接口詳細(xì)的介紹可以看下之前的文章。
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 不存在的鍵值對(duì)時(shí),不會(huì)報(bào)錯(cuò)爆雹,相當(dāng)于沒(méi)有任何作用停蕉;獲取不存在的減值對(duì)時(shí)愕鼓,返回值類型對(duì)應(yīng)的零值,所以返回 0慧起。
27.下面屬于關(guān)鍵字的是()
A.func
B.struct
C.class
D.defer
參考答案及解析:ABD菇晃。知識(shí)點(diǎn):Go 語(yǔ)言的關(guān)鍵字。Go 語(yǔ)言有 25 個(gè)關(guān)鍵字蚓挤,看下圖:
28.下面這段代碼輸出什么磺送?
func main() {
i := -5
j := +5
fmt.Printf("%+d %+d", i, j)
}
A. -5 +5
B. +5 +5
C. 0 0
參考答案及解析:A。%d表示輸出十進(jìn)制數(shù)字灿意,+表示輸出數(shù)值的符號(hào)估灿。這里不表示取反。
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馅袁。知識(shí)點(diǎn):結(jié)構(gòu)體嵌套。在嵌套結(jié)構(gòu)體中荒辕,People 稱為內(nèi)部類型汗销,Teacher 稱為外部類型;通過(guò)嵌套兄纺,內(nèi)部類型的屬性大溜、方法,可以為外部類型所有估脆,就好像是外部類型自己的一樣钦奋。此外,外部類型還可以定義自己的屬性和方法疙赠,甚至可以定義與內(nèi)部相同的方法付材,這樣內(nèi)部類型的方法就會(huì)被“屏蔽”。這個(gè)例子中的 ShowB() 就是同名方法圃阳。
30.定義一個(gè)包內(nèi)全局字符串變量厌衔,下面語(yǔ)法正確的是()
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
知識(shí)點(diǎn):結(jié)構(gòu)體嵌套锣夹。這道題可以結(jié)合第 12 天的第三題一起看页徐,Teacher 沒(méi)有自己 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。這個(gè)例子中贴唇,hello() 函數(shù)的參數(shù)在執(zhí)行 defer 語(yǔ)句的時(shí)候會(huì)保存一份副本搀绣,在實(shí)際調(diào)用 hello() 函數(shù)時(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.對(duì) 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.下面代碼下劃線處可以填入哪個(gè)選項(xiàng)链患?
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 編碼中蹄皱,十進(jìn)制數(shù)字 65 對(duì)應(yīng)的符號(hào)是 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。知識(shí)點(diǎn):接口压鉴。一種類型實(shí)現(xiàn)多個(gè)接口崖咨,結(jié)構(gòu)體 Work 分別實(shí)現(xiàn)了接口 A、B油吭,所以接口變量 a击蹲、b 調(diào)用各自的方法 ShowA() 和 ShowB(),輸出 13婉宰、23歌豺。
39.切片 a、b心包、c 的長(zhǎng)度和容量分別是多少类咧?
func main() {
s := [3]int{1, 2, 3}
a := s[:0]
b := s[:2]
c := s[1:2:cap(s)]
}
參考答案及解析:a、b蟹腾、c 的長(zhǎng)度和容量分別是 0 3痕惋、2 3、1 2娃殖。知識(shí)點(diǎn):數(shù)組或切片的截取操作值戳。截取操作有帶 2 個(gè)或者 3 個(gè)參數(shù),形如:[i:j] 和 [i:j:k]炉爆,假設(shè)截取對(duì)象的底層數(shù)組長(zhǎng)度為 l堕虹。在操作符 [i:j] 中,如果 i 省略芬首,默認(rèn) 0赴捞,如果 j 省略,默認(rèn)底層數(shù)組的長(zhǎng)度衩辟,截取得到的切片長(zhǎng)度和容量計(jì)算方法是 j-i螟炫、l-i。操作符 [i:j:k]艺晴,k 主要是用來(lái)限制切片的容量昼钻,但是不能大于數(shù)組的長(zhǎng)度 l掸屡,截取得到的切片長(zhǎng)度和容量計(jì)算方法是 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 ,并沒(méi)有分配內(nèi)存空間仅财,不能直接賦值,需要使用 make()碗淌,都提倡使用 make() 或者字面量的方式直接初始化 map盏求。
B 處,v,k := m["b"] 當(dāng) key 為 b 的元素不存在的時(shí)候亿眠,v 會(huì)返回值類型對(duì)應(yīng)的零值碎罚,k 返回 false。
- 下面代碼輸出什么纳像?
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荆烈。知識(shí)點(diǎn):接口的靜態(tài)類型。a竟趾、b 具有相同的動(dòng)態(tài)類型和動(dòng)態(tài)值憔购,分別是結(jié)構(gòu)體 work 和 {3};a 的靜態(tài)類型是 A岔帽,b 的靜態(tài)類型是 B玫鸟,接口 A 不包括方法 ShowB(),接口 B 也不包括方法 ShowA()犀勒,編譯報(bào)錯(cuò)屎飘。看下編譯錯(cuò)誤:
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 沒(méi)有聲明,判斷每條語(yǔ)句的對(duì)錯(cuò)铸本。
1. x, _ := f()
2. x, _ = f()
3. x, y := f()
4. x, y = f()
參考答案及解析:錯(cuò)肮雨、對(duì)、對(duì)箱玷、錯(cuò)怨规。知識(shí)點(diǎn):變量的聲明。1.錯(cuò)锡足,x 已經(jīng)聲明波丰,不能使用 :=;2.對(duì)舶得;3.對(duì)掰烟,當(dāng)多值賦值時(shí),:= 左邊的變量無(wú)論聲明與否都可以;4.錯(cuò)纫骑,y 沒(méi)有聲明蝎亚。
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 類型斷言可以用來(lái)獲取接口的底層值发框, 通常的語(yǔ)法:i.(Type), 其中i是接口,其實(shí)i是接口煤墙,Type是類型或接口梅惯。編譯時(shí)會(huì)自動(dòng)檢測(cè)i的動(dòng)態(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.下面的兩個(gè)切片聲明中有什么區(qū)別徙歼?哪個(gè)更可取鳖枕?
A. var a []int
B. a := []int{}
.參考答案及解析:A 聲明的是 nil 切片;B 聲明的是長(zhǎng)度和容量都為 0 的空切片桨螺。第一種切片聲明不會(huì)分配內(nèi)存宾符,優(yōu)先選擇
50.A、B灭翔、C魏烫、D 哪些選項(xiàng)有語(yǔ)法錯(cuò)誤?
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 類型档玻,不過(guò)都可以使用 p.m 取得結(jié)構(gòu)體的成員
52.下面的代碼各有幾處語(yǔ)法問(wèn)題怀泊,各是什么失都?
package main
import (
"fmt"
)
func main() {
var x string = nil
if x == nil {
x = "default"
}
fmt.Println(x)
}
string 不能是nil 不能和nil 比較
53.return 之后的 defer 語(yǔ)句會(huì)執(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í)行必須先注冊(cè),return 之后的 defer 是不能注冊(cè)的枣申, 也就不能執(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ù)組。當(dāng)使用 s1[1:] 獲得切片 s2熄驼,和 s1 共享同一個(gè)底層數(shù)組像寒,這會(huì)導(dǎo)致 s2[1] = 4 語(yǔ)句影響 s1。
而 append 操作會(huì)導(dǎo)致底層數(shù)組擴(kuò)容瓜贾,生成新的數(shù)組诺祸,因此追加數(shù)據(jù)后的 s2 不會(huì)影響 s1。
但是為什么對(duì) s2 賦值后影響的卻是 s1 的第三個(gè)元素呢祭芦?這是因?yàn)榍衅?s2 是從數(shù)組的第二個(gè)元素開始筷笨,s2 索引為 1 的元素對(duì)應(yīng)的是 s1 索引為 2 的元素。
55.下面選項(xiàng)正確的是龟劲?
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ù)三行代碼的時(shí)候昌跌,會(huì)先執(zhí)行 calc() 函數(shù)的 b 參數(shù)仰禀,即:calc("10",a,b),輸出:10 1 2 3蚕愤,得到值 3答恶,因?yàn)?br>
defer 定義的函數(shù)是延遲函數(shù),故 calc("1",1,3) 會(huì)被延遲執(zhí)行萍诱;
程序執(zhí)行到第五行的時(shí)候悬嗓,同樣先執(zhí)行 calc("20",a,b) 輸出:20 0 2 2 得到值 2,同樣將 calc("2",0,2) 延遲執(zhí)行裕坊;
程序執(zhí)行到末尾的時(shí)候包竹,按照棧先進(jìn)后出的方式依次執(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)建的方法必須定義在同一個(gè)包內(nèi)苹享,上面的代碼基于 int 類型創(chuàng)建了 PrintInt() 方法双絮,由于 int 類型和方法 PrintInt() 定義在不同的包內(nèi)浴麻,所以編譯出錯(cuò)。
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。編譯錯(cuò)誤 Student does not implement People (Speak method has pointer receiver)焚挠,值類型 Student 沒(méi)有實(shí)現(xiàn)接口的 Speak() 方法膏萧,而是指針類型 *Student 實(shí)現(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
知識(shí)點(diǎn):iota 的用法榛泛。
iota 是 golang 語(yǔ)言的常量計(jì)數(shù)器,只能在常量的表達(dá)式中使用噩斟。
iota 在 const 關(guān)鍵字出現(xiàn)時(shí)將被重置為0曹锨,const中每新增一行常量聲明將使 iota 計(jì)數(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。這道題會(huì)不會(huì)有點(diǎn)詫異斥废,我們分配給變量 p 的值明明是 nil椒楣,然而 p 卻不是 nil。記住一點(diǎn)牡肉,當(dāng)且僅當(dāng)動(dòng)態(tài)值和動(dòng)態(tài)類型都為 nil 時(shí)撒顿,接口類型值才為 nil。上面的代碼荚板,給變量 p 賦值之后,p 的動(dòng)態(tài)值是 nil吩屹,但是動(dòng)態(tài)類型卻是 *Student跪另,是一個(gè) 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。知識(shí)點(diǎn):iota 的用法擦盾、類型的 String() 方法嘲驾。
根據(jù) iota 的用法推斷出 South 的值是 3;另外迹卢,如果類型定義了 String() 方法辽故,當(dāng)使用 fmt.Printf()、fmt.Print() 和 fmt.Println() 會(huì)自動(dòng)使用 String() 方法腐碱,實(shí)現(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,編譯報(bào)錯(cuò) cannot assign to struct field m["foo"].x in map喂走。錯(cuò)誤原因:對(duì)于類似 X = Y的賦值操作殃饿,必須知道 X 的地址,才能夠?qū)?Y 的值賦給 X芋肠,但 go 中的 map 的 value 本身是不可尋址的乎芳。
有兩個(gè)解決辦法:
使用臨時(shí)變量
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 格式化輸出詳細(xì)信息
}
64.下面的代碼有什么問(wèn)題?
func main() {
fmt.Println([...]int{1} == [2]int{1})
fmt.Println([]int{1} == []int{1})
}
參考答案及解析:有兩處錯(cuò)誤
go 中不同類型是不能比較的,而數(shù)組長(zhǎng)度是數(shù)組類型的一部分帖池,所以 […]int{1} 和 [2]int{1} 是兩種不同的類型奈惑,不能比較;
切片是不能比較的碘裕;
65.下面這段代碼輸出什么携取?如果編譯錯(cuò)誤的話,為什么帮孔?
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雷滋。知識(shí)點(diǎn):變量作用域。問(wèn)題出在操作符:=文兢,對(duì)于使用:=定義的變量晤斩,如果新變量與同名已定義的變量不在同一個(gè)作用域中,那么 Go 會(huì)新定義這個(gè)變量姆坚。對(duì)于本例來(lái)說(shuō)澳泵,main() 函數(shù)里的 p 是新定義的變量,會(huì)遮住全局變量 p兼呵,導(dǎo)致執(zhí)行到bar()時(shí)程序兔辅,全局變量 p 依然還是 nil,程序隨即 Crash击喂。