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
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
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
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]\
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]
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ǔ),我們下期見~