-
Notifications
You must be signed in to change notification settings - Fork 135
/
91-120.md
850 lines (622 loc) · 19.9 KB
/
91-120.md
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
> 目录
>
> * [91\. 下面代码输出什么?](#91-%E4%B8%8B%E9%9D%A2%E4%BB%A3%E7%A0%81%E8%BE%93%E5%87%BA%E4%BB%80%E4%B9%88)
> * [92\. 下面这段代码能否编译通过?如果通过,输出什么?](#92-%E4%B8%8B%E9%9D%A2%E8%BF%99%E6%AE%B5%E4%BB%A3%E7%A0%81%E8%83%BD%E5%90%A6%E7%BC%96%E8%AF%91%E9%80%9A%E8%BF%87%E5%A6%82%E6%9E%9C%E9%80%9A%E8%BF%87%E8%BE%93%E5%87%BA%E4%BB%80%E4%B9%88)
> * [93\. 关于无缓冲和有冲突的channel,下面说法正确的是?](#93-%E5%85%B3%E4%BA%8E%E6%97%A0%E7%BC%93%E5%86%B2%E5%92%8C%E6%9C%89%E5%86%B2%E7%AA%81%E7%9A%84channel%E4%B8%8B%E9%9D%A2%E8%AF%B4%E6%B3%95%E6%AD%A3%E7%A1%AE%E7%9A%84%E6%98%AF)
> * [94\. 下面代码是否能编译通过?如果通过,输出什么?](#94-%E4%B8%8B%E9%9D%A2%E4%BB%A3%E7%A0%81%E6%98%AF%E5%90%A6%E8%83%BD%E7%BC%96%E8%AF%91%E9%80%9A%E8%BF%87%E5%A6%82%E6%9E%9C%E9%80%9A%E8%BF%87%E8%BE%93%E5%87%BA%E4%BB%80%E4%B9%88)
> * [95\. 下面代码输出什么?](#95-%E4%B8%8B%E9%9D%A2%E4%BB%A3%E7%A0%81%E8%BE%93%E5%87%BA%E4%BB%80%E4%B9%88)
> * [96\. 关于select机制,下面说法正确的是?](#96-%E5%85%B3%E4%BA%8Eselect%E6%9C%BA%E5%88%B6%E4%B8%8B%E9%9D%A2%E8%AF%B4%E6%B3%95%E6%AD%A3%E7%A1%AE%E7%9A%84%E6%98%AF)
> * [97\. 下面的代码有什么问题?](#97-%E4%B8%8B%E9%9D%A2%E7%9A%84%E4%BB%A3%E7%A0%81%E6%9C%89%E4%BB%80%E4%B9%88%E9%97%AE%E9%A2%98)
> * [98\. 下面这段代码存在什么问题?](#98-%E4%B8%8B%E9%9D%A2%E8%BF%99%E6%AE%B5%E4%BB%A3%E7%A0%81%E5%AD%98%E5%9C%A8%E4%BB%80%E4%B9%88%E9%97%AE%E9%A2%98)
> * [99\. 下面代码编译能通过吗?](#99-%E4%B8%8B%E9%9D%A2%E4%BB%A3%E7%A0%81%E7%BC%96%E8%AF%91%E8%83%BD%E9%80%9A%E8%BF%87%E5%90%97)
> * [100\. 下面这段代码输出什么?](#100-%E4%B8%8B%E9%9D%A2%E8%BF%99%E6%AE%B5%E4%BB%A3%E7%A0%81%E8%BE%93%E5%87%BA%E4%BB%80%E4%B9%88)
> * [101\. 下面这段代码输出什么?](#101-%E4%B8%8B%E9%9D%A2%E8%BF%99%E6%AE%B5%E4%BB%A3%E7%A0%81%E8%BE%93%E5%87%BA%E4%BB%80%E4%B9%88)
> * [102\. 请指出下面代码的错误?](#102-%E8%AF%B7%E6%8C%87%E5%87%BA%E4%B8%8B%E9%9D%A2%E4%BB%A3%E7%A0%81%E7%9A%84%E9%94%99%E8%AF%AF)
> * [103\. 下面代码输出什么?](#103-%E4%B8%8B%E9%9D%A2%E4%BB%A3%E7%A0%81%E8%BE%93%E5%87%BA%E4%BB%80%E4%B9%88)
> * [104\. 下面代码输出什么?](#104-%E4%B8%8B%E9%9D%A2%E4%BB%A3%E7%A0%81%E8%BE%93%E5%87%BA%E4%BB%80%E4%B9%88)
> * [105\. 下面的代码有什么问题?](#105-%E4%B8%8B%E9%9D%A2%E7%9A%84%E4%BB%A3%E7%A0%81%E6%9C%89%E4%BB%80%E4%B9%88%E9%97%AE%E9%A2%98)
> * [106\. 下面代码输出什么?](#106-%E4%B8%8B%E9%9D%A2%E4%BB%A3%E7%A0%81%E8%BE%93%E5%87%BA%E4%BB%80%E4%B9%88)
> * [107\. 下面代码有几处错误的地方?请说明原因。](#107-%E4%B8%8B%E9%9D%A2%E4%BB%A3%E7%A0%81%E6%9C%89%E5%87%A0%E5%A4%84%E9%94%99%E8%AF%AF%E7%9A%84%E5%9C%B0%E6%96%B9%E8%AF%B7%E8%AF%B4%E6%98%8E%E5%8E%9F%E5%9B%A0)
> * [108\. 下面代码有什么问题?](#108-%E4%B8%8B%E9%9D%A2%E4%BB%A3%E7%A0%81%E6%9C%89%E4%BB%80%E4%B9%88%E9%97%AE%E9%A2%98)
> * [109\. 下面的代码有什么问题?](#109-%E4%B8%8B%E9%9D%A2%E7%9A%84%E4%BB%A3%E7%A0%81%E6%9C%89%E4%BB%80%E4%B9%88%E9%97%AE%E9%A2%98)
> * [110\. 下面代码能编译通过吗?](#110-%E4%B8%8B%E9%9D%A2%E4%BB%A3%E7%A0%81%E8%83%BD%E7%BC%96%E8%AF%91%E9%80%9A%E8%BF%87%E5%90%97)
> * [111\. 下面代码有什么错误?](#111-%E4%B8%8B%E9%9D%A2%E4%BB%A3%E7%A0%81%E6%9C%89%E4%BB%80%E4%B9%88%E9%94%99%E8%AF%AF)
> * [112\. 下面代码有什么问题?](#112-%E4%B8%8B%E9%9D%A2%E4%BB%A3%E7%A0%81%E6%9C%89%E4%BB%80%E4%B9%88%E9%97%AE%E9%A2%98)
> * [113\. 下面代码输出什么?](#113-%E4%B8%8B%E9%9D%A2%E4%BB%A3%E7%A0%81%E8%BE%93%E5%87%BA%E4%BB%80%E4%B9%88)
> * [114\. 下面的代码有什么问题?](#114-%E4%B8%8B%E9%9D%A2%E7%9A%84%E4%BB%A3%E7%A0%81%E6%9C%89%E4%BB%80%E4%B9%88%E9%97%AE%E9%A2%98)
> * [115\. 下面代码输出什么?](#115-%E4%B8%8B%E9%9D%A2%E4%BB%A3%E7%A0%81%E8%BE%93%E5%87%BA%E4%BB%80%E4%B9%88)
> * [116\. 下面代码有什么问题?](#116-%E4%B8%8B%E9%9D%A2%E4%BB%A3%E7%A0%81%E6%9C%89%E4%BB%80%E4%B9%88%E9%97%AE%E9%A2%98)
> * [117\. 下面的代码有什么问题?](#117-%E4%B8%8B%E9%9D%A2%E7%9A%84%E4%BB%A3%E7%A0%81%E6%9C%89%E4%BB%80%E4%B9%88%E9%97%AE%E9%A2%98)
> * [118\. 下面代码最后一行输出什么?请说明原因。](#118-%E4%B8%8B%E9%9D%A2%E4%BB%A3%E7%A0%81%E6%9C%80%E5%90%8E%E4%B8%80%E8%A1%8C%E8%BE%93%E5%87%BA%E4%BB%80%E4%B9%88%E8%AF%B7%E8%AF%B4%E6%98%8E%E5%8E%9F%E5%9B%A0)
> * [119\. 下面代码有什么问题?](#119-%E4%B8%8B%E9%9D%A2%E4%BB%A3%E7%A0%81%E6%9C%89%E4%BB%80%E4%B9%88%E9%97%AE%E9%A2%98)
> * [120\. 下面的代码输出什么?](#120-%E4%B8%8B%E9%9D%A2%E7%9A%84%E4%BB%A3%E7%A0%81%E8%BE%93%E5%87%BA%E4%BB%80%E4%B9%88)
> * [121\. 121-150题](https://github.com/yqchilde/Golang-Interview/blob/master/121-150.md)
## 91. 下面代码输出什么?
```go
func main() {
x := []string{"a", "b", "c"}
for v := range x {
fmt.Print(v)
}
}
```
**答:012**
**解析:**
注意区别下面代码段:
```go
func main() {
x := []string{"a", "b", "c"}
for _, v := range x {
fmt.Print(v) //输出 abc
}
}
```
## 92. 下面这段代码能否编译通过?如果通过,输出什么?
```go
type User struct{}
type User1 User
type User2 = User
func (i User) m1() {
fmt.Println("m1")
}
func (i User) m2() {
fmt.Println("m2")
}
func main() {
var i1 User1
var i2 User2
i1.m1()
i2.m2()
}
```
**答:不能,报错`i1.m1 undefined (type User1 has no field or method m1)`**
**解析:**
第 2 行代码基于类型 User 创建了新类型 User1,第 3 行代码是创建了 User 的类型别名 User2,注意使用 = 定义类型别名。因为 User2 是别名,完全等价于 User,所以 User2 具有 User 所有的方法。但是 i1.m1() 是不能执行的,因为 User1 没有定义该方法。
## 93. 关于无缓冲和有冲突的channel,下面说法正确的是?
- A. 无缓冲的channel是默认的缓冲为1的channel;
- B. 无缓冲的channel和有缓冲的channel都是同步的;
- C. 无缓冲的channel和有缓冲的channel都是非同步的;
- D. 无缓冲的channel是同步的,而有缓冲的channel是非同步的;
**答:D**
## 94. 下面代码是否能编译通过?如果通过,输出什么?
```go
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**
**解析:**
考点:interface 的内部结构,我们知道接口除了有静态类型,还有动态类型和动态值,当且仅当动态值和动态类型都为 nil 时,接口类型值才为 nil。这里的 x 的动态类型是 `*int`,所以 x 不为 nil。
## 95. 下面代码输出什么?
```go
func main() {
ch := make(chan int, 100)
// A
go func() {
for i := 0; i < 10; i++ {
ch <- i
}
}()
// B
go func() {
for {
a, ok := <-ch
if !ok {
fmt.Println("close")
return
}
fmt.Println("a: ", a)
}
}()
close(ch)
fmt.Println("ok")
time.Sleep(time.Second * 10)
}
```
**答:程序抛异常**
**解析:**
先定义下,第一个协程为 A 协程,第二个协程为 B 协程;当 A 协程还没起时,主协程已经将 channel 关闭了,当 A 协程往关闭的 channel 发送数据时会 panic,`panic: send on closed channel`。
## 96. 关于select机制,下面说法正确的是?
- A. select机制用来处理异步IO问题;
- B. select机制最大的一条限制就是每个case语句里必须是一个IO操作;
- C. golang在语言级别支持select关键字;
- D. select关键字的用法与switch语句非常类似,后面要带判断条件;
**答:A B C**
## 97. 下面的代码有什么问题?
```go
func Stop(stop <-chan bool) {
close(stop)
}
```
**答:有方向的 channel 不可以被关闭。**
## 98. 下面这段代码存在什么问题?
```go
type Param map[string]interface{}
type Show struct {
*Param
}
func main() {
s := new(Show)
s.Param["day"] = 2
}
```
**答:存在两个问题**
**解析:**
1. map 需要初始化才能使用;
2. 指针不支持索引。修复代码如下:
```go
func main() {
s := new(Show)
// 修复代码
p := make(Param)
p["day"] = 2
s.Param = &p
tmp := *s.Param
fmt.Println(tmp["day"])
}
```
## 99. 下面代码编译能通过吗?
```go
func main()
{
fmt.Println("hello world")
}
```
**答:编译错误**
```shell
syntax error: unexpected semicolon or newline before {
```
**解析:**
Go 语言中,大括号不能放在单独的一行。
正确的代码如下:
```go
func main() {
fmt.Println("works")
}
```
## 100. 下面这段代码输出什么?
```go
var x = []int{2: 2, 3, 0: 1}
func main() {
fmt.Println(x)
}
```
**答:[1 0 2 3]**
**解析:**
字面量初始化切片时候,可以指定索引,没有指定索引的元素会在前一个索引基础之上加一,所以输出`[1 0 2 3]`,而不是`[1 3 2]`。
## 101. 下面这段代码输出什么?
```go
func incr(p *int) int {
*p++
return *p
}
func main() {
v := 1
incr(&v)
fmt.Println(v)
}
```
**答:2**
**解析:**
知识点:指针。
p 是指针变量,指向变量 v,`*p++`操作的意思是取出变量 v 的值并执行加一操作,所以 v 的最终值是 2。
## 102. 请指出下面代码的错误?
```go
package main
var gvar int
func main() {
var one int
two := 2
var three int
three = 3
func(unused string) {
fmt.Println("Unused arg. No compile error")
}("what?")
}
```
**答:变量 one、two 和 three 声明未使用**
**解析:**
知识点:**未使用变量**。
如果有未使用的变量代码将编译失败。但也有例外,函数中声明的变量必须要使用,但可以有未使用的全局变量。函数的参数未使用也是可以的。
如果你给未使用的变量分配了一个新值,代码也还是会编译失败。你需要在某个地方使用这个变量,才能让编译器愉快的编译。
修复代码:
```go
func main() {
var one int
_ = one
two := 2
fmt.Println(two)
var three int
three = 3
one = three
var four int
four = four
}
```
另一个选择是注释掉或者移除未使用的变量 。
## 103. 下面代码输出什么?
```go
type ConfigOne struct {
Daemon string
}
func (c *ConfigOne) String() string {
return fmt.Sprintf("print: %v", c)
}
func main() {
c := &ConfigOne{}
c.String()
}
```
**答:运行时错误**
**解析:**
如果类型实现 String() 方法,当格式化输出时会自动使用 String() 方法。上面这段代码是在该类型的 String() 方法内使用格式化输出,导致递归调用,最后抛错。
```shell
runtime: goroutine stack exceeds 1000000000-byte limit
fatal error: stack overflow
```
## 104. 下面代码输出什么?
```go
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]**
**解析:**
a 在 for range 过程中增加了两个元素,len 由 5 增加到 7,但 for range 时会使用 a 的副本 a' 参与循环,副本的 len 依旧是 5,因此 for range 只会循环 5 次,也就只获取 a 对应的底层数组的前 5 个元素。
## 105. 下面的代码有什么问题?
```go
import (
"fmt"
"log"
"time"
)
func main() {
}
```
**答:导入的包没有被使用**
**解析:**
如果引入一个包,但是未使用其中如何函数、接口、结构体或变量的话,代码将编译失败。
如果你真的需要引入包,可以使用下划线操作符,`_`,来作为这个包的名字,从而避免失败。下划线操作符用于引入,但不使用。
我们还可以注释或者移除未使用的包。
修复代码:
```go
import (
_ "fmt"
"log"
"time"
)
var _ = log.Println
func main() {
_ = time.Now
}
```
## 106. 下面代码输出什么?
```go
func main() {
x := interface{}(nil)
y := (*int)(nil)
a := y == x
b := y == nil
_, c := x.(interface{})
println(a, b, c)
}
```
- A. true true true
- B. false true true
- C. true true true
- D. false true false
**答:D**
**解析:**
知识点:类型断言。
类型断言语法:i.(Type),其中 i 是接口,Type 是类型或接口。编译时会自动检测 i 的动态类型与 Type 是否一致。但是,如果动态类型不存在,则断言总是失败。
## 107. 下面代码有几处错误的地方?请说明原因。
```go
func main() {
var s []int
s = append(s,1)
var m map[string]int
m["one"] = 1
}
```
**答:有 1 处错误**
**解析:**
有 1 处错误,不能对 nil 的 map 直接赋值,需要使用 make() 初始化。但可以使用 append() 函数对为 nil 的 slice 增加元素。
修复代码:
```go
func main() {
var m map[string]int
m = make(map[string]int)
m["one"] = 1
}
```
## 108. 下面代码有什么问题?
```go
func main() {
m := make(map[string]int,2)
cap(m)
}
```
**答:使用 cap() 获取 map 的容量**
**解析:**
1. 使用 make 创建 map 变量时可以指定第二个参数,不过会被忽略。
2. cap() 函数适用于数组、数组指针、slice 和 channel,不适用于 map,可以使用 len() 返回 map 的元素个数。
## 109. 下面的代码有什么问题?
```go
func main() {
var x = nil
_ = x
}
```
**解析:**
nil 用于表示 interface、函数、maps、slices 和 channels 的“零值”。如果不指定变量的类型,编译器猜不出变量的具体类型,导致编译错误。
修复代码:
```go
func main() {
var x interface{} = nil
_ = x
}
```
## 110. 下面代码能编译通过吗?
```go
type info struct {
result int
}
func work() (int,error) {
return 13,nil
}
func main() {
var data info
data.result, err := work()
fmt.Printf("info: %+v\n",data)
}
```
**答:编译失败**
```shell
non-name data.result on left side of :=
```
**解析:**
不能使用短变量声明设置结构体字段值,修复代码:
```go
func main() {
var data info
var err error
data.result, err = work() //ok
if err != nil {
fmt.Println(err)
return
}
fmt.Println(data)
}
```
## 111. 下面代码有什么错误?
```go
func main() {
one := 0
one := 1
}
```
**答:变量重复声明**
**解析:**
不能在单独的声明中重复声明一个变量,但在多变量声明的时候是可以的,但必须保证至少有一个变量是新声明的。
修复代码:
```go
func main() {
one := 0
one, two := 1,2
one,two = two,one
}
```
## 112. 下面代码有什么问题?
```go
func main() {
x := []int{
1,
2
}
_ = x
}
```
**答:编译错误**
**解析:**
第四行代码没有逗号。用字面量初始化数组、slice 和 map 时,最好是在每个元素后面加上逗号,即使是声明在一行或者多行都不会出错。
修复代码:
```go
func main() {
x := []int{ // 多行
1,
2,
}
x = x
y := []int{3,4,} // 一行 no error
y = y
}
```
## 113. 下面代码输出什么?
```go
func test(x byte) {
fmt.Println(x)
}
func main() {
var a byte = 0x11
var b uint8 = a
var c uint8 = a + b
test(c)
}
```
**答:34**
**解析:**
与 rune 是 int32 的别名一样,byte 是 uint8 的别名,别名类型无序转换,可直接转换。
## 114. 下面的代码有什么问题?
```go
func main() {
const x = 123
const y = 1.23
fmt.Println(x)
}
```
**答:编译可以通过**
**解析:**
知识点:常量。
常量是一个简单值的标识符,在程序运行时,不会被修改的量。不像变量,常量未使用是能编译通过的。
## 115. 下面代码输出什么?
```go
const (
x uint16 = 120
y
s = "abc"
z
)
func main() {
fmt.Printf("%T %v\n", y, y)
fmt.Printf("%T %v\n", z, z)
}
```
**答:**
```shell
uint16 120
string abc
```
**解析:**
常量组中如不指定类型和初始化值,则与上一行非空常量右值相同
## 116. 下面代码有什么问题?
```go
func main() {
var x string = nil
if x == nil {
x = "default"
}
}
```
**答:将 nil 分配给 string 类型的变量**
**解析:**
修复代码:
```go
func main() {
var x string //defaults to "" (zero value)
if x == "" {
x = "default"
}
}
```
## 117. 下面的代码有什么问题?
```go
func main() {
data := []int{1,2,3}
i := 0
++i
fmt.Println(data[i++])
}
```
**解析:**
对于自增、自减,需要注意:
- 自增、自减不在是运算符,只能作为独立语句,而不是表达式;
- 不像其他语言,Go 语言中不支持 ++i 和 --i 操作;
表达式通常是求值代码,可作为右值或参数使用。而语句表示完成一个任务,比如 if、for 语句等。表达式可作为语句使用,但语句不能当做表达式。
修复代码:
```go
func main() {
data := []int{1,2,3}
i := 0
i++
fmt.Println(data[i])
}
```
## 118. 下面代码最后一行输出什么?请说明原因。
```go
func main() {
x := 1
fmt.Println(x)
{
fmt.Println(x)
i,x := 2,2
fmt.Println(i,x)
}
fmt.Println(x) // print ?
}
```
**答:输出`1`**
**解析:**
知识点:变量隐藏。
使用变量简短声明符号 := 时,如果符号左边有多个变量,只需要保证至少有一个变量是新声明的,并对已定义的变量尽进行赋值操作。但如果出现作用域之后,就会导致变量隐藏的问题,就像这个例子一样。
这个坑很容易挖,但又很难发现。即使对于经验丰富的 Go 开发者而言,这也是一个非常常见的陷阱。
## 119. 下面代码有什么问题?
```go
type foo struct {
bar int
}
func main() {
var f foo
f.bar, tmp := 1, 2
}
```
**答:编译错误**
```shell
non-name f.bar on left side of :=
```
**解析:**
`:=` 操作符不能用于结构体字段赋值。
## 120. 下面的代码输出什么?
```go
func main() {
fmt.Println(~2)
}
```
**答:编译错误**
```shell
invalid character U+007E '~'
```
**解析:**
很多语言都是采用 `~` 作为按位取反运算符,Go 里面采用的是` ^` 。按位取反之后返回一个每个 bit 位都取反的数,对于有符号的整数来说,是按照补码进行取反操作的(快速计算方法:对数 a 取反,结果为 -(a+1) ),对于无符号整数来说就是按位取反。例如:
```go
func main() {
var a int8 = 3
var b uint8 = 3
var c int8 = -3
fmt.Printf("^%b=%b %d\n", a, ^a, ^a) // ^11=-100 -4
fmt.Printf("^%b=%b %d\n", b, ^b, ^b) // ^11=11111100 252
fmt.Printf("^%b=%b %d\n", c, ^c, ^c) // ^-11=10 2
}
```
另外需要注意的是,如果作为二元运算符,^ 表示按位异或,即:对应位相同为 0,相异为 1。例如:
```go
func main() {
var a int8 = 3
var c int8 = 5
fmt.Printf("a: %08b\n",a)
fmt.Printf("c: %08b\n",c)
fmt.Printf("a^c: %08b\n",a ^ c)
}
```
给大家重点介绍下这个操作符 &^,按位置零,例如:z = x &^ y,表示如果 y 中的 bit 位为 1,则 z 对应 bit 位为 0,否则 z 对应 bit 位等于 x 中相应的 bit 位的值。
不知道大家发现没有,我们还可以这样理解或操作符 | ,表达式 z = x | y,如果 y 中的 bit 位为 1,则 z 对应 bit 位为 1,否则 z 对应 bit 位等于 x 中相应的 bit 位的值,与 &^ 完全相反。
```go
var x uint8 = 214
var y uint8 = 92
fmt.Printf("x: %08b\n",x)
fmt.Printf("y: %08b\n",y)
fmt.Printf("x | y: %08b\n",x | y)
fmt.Printf("x &^ y: %08b\n",x &^ y)
```
输出:
```shell
x: 11010110
y: 01011100
x | y: 11011110
x &^ y: 10000010
```