33. 【中级】 golang中的引用类型包括()
A. 数组切片
B. map
C. channel
D. interface
参考答案:ABCD
这道题已经过时了,在2013年4月3日的github提交中已经明确说了“Go has no 'reference types'”。而slice源码的说明也由“引用”改成了“描述符”。Go只有值传递,没有所谓的引用传递。上题应该改为哪些类型包含有指针。
34. 【中级】 golang中的指针运算包括()
A. 可以对指针进行自增或自减运算
B. 可以通过“&”取指针的地址
C. 可以通过“*”取指针指向的数据
D. 可以对指针进行下标运算
参考答案:BC
D选项应该也是对的,在Go13.8里指向数组的指针的下标运算是可以支持的:
package main
import "fmt"
func main() {
var a = [3]int{998, 999, 1000}
var ip *[3]int = &a
for i := 0; i < len(a); i++ {
fmt.Printf("ip[%d]=%d\n", i, ip[i])
}
}
输出:
ip[0]=998
ip[1]=999
ip[2]=1000
36. 【中级】下面赋值正确的是()
A. var x = nil
B. var x interface{} = nil
C. var x string = nil
D. var x error = nil
参考答案:BD
可以赋值成nil的变量类型有7种:1)任意类型的指针变量,2)函数变量,3)接口,4)error,5)map, 6)切片 7)通道。这些变量默认值就是nil,实际上都不用赋值成nil。
package main
import "fmt"
func main() {
var ptrI *int
var f func()
var iface interface{}
var err error
var m map[string]string
var sl []string
var ch chan int
if ptrI == nil {fmt.Printf("1) pointer is nil\n")}
if f == nil {fmt.Printf("2) func is nil\n")}
if iface == nil {fmt.Printf("3) interface is nil\n")}
if err == nil {fmt.Printf("4) error is nil\n")}
if m == nil {fmt.Printf("5) map is nil\n")}
if sl == nil {fmt.Printf("6) slice is nil\n")}
if ch == nil {fmt.Printf("7) ch is nil\n")}
}
输出:
1) pointer is nil
2) func is nil
3) interface is nil
4) error is nil
5) map is nil
6) slice is nil
7) ch is nil
不能赋值成nil的变量类型,会在编译时报错:
package main
import "fmt"
type Person struct {
name string
}
func main() {
var str string = nil
var person Person = nil
var i int = nil
var b bool = nil
var x = nil
fmt.Printf("str=%v person=%v i=%v b=%v x=%v", str, person, i, b, x)
}
编译报错:
# command-line-arguments
./tryinit.go:10:6: cannot use nil as type string in assignment
./tryinit.go:11:6: cannot use nil as type Person in assignment
./tryinit.go:12:6: cannot use nil as type int in assignment
./tryinit.go:13:6: use of untyped nil
38. 【中级】从切片中删除一个元素,下面的算法实现正确的是()
A.
func (s *Slice)Remove(value interface{})error {
for i, v := range *s {
if isEqual(value, v) {
if i== len(*s) - 1 {
*s = (*s)[:i]
}else {
*s = append((*s)[:i],(*s)[i + 2:]...)
}
return nil
}
}
return ERR_ELEM_NT_EXIST
}
B.
func (s*Slice)Remove(value interface{}) error {
for i, v:= range *s {
if isEqual(value, v) {
*s =append((*s)[:i],(*s)[i + 1:])
return nil
}
}
returnERR_ELEM_NT_EXIST
}
C.
func (s*Slice)Remove(value interface{}) error {
for i, v:= range *s {
if isEqual(value, v) {
delete(*s, v)
return nil
}
}
returnERR_ELEM_NT_EXIST
}
D.
func (s*Slice)Remove(value interface{}) error {
for i, v:= range *s {
if isEqual(value, v) {
*s =append((*s)[:i],(*s)[i + 1:]...)
return nil
}
}
returnERR_ELEM_NT_EXIST
}
参考答案:D
A,切片截取是前闭后开;B,append追加另一个切片时需要加"...";C,delete是map的删除方式
51. 【初级】对于局部变量整型切片x的赋值,下面定义正确的是()
A. x := []int{
1, 2, 3,
4, 5, 6,
}
B. x :=[]int{
1, 2, 3,
4, 5, 6
}
C. x :=[]int{
1, 2, 3,
4, 5, 6}
D. x :=[]int{1, 2, 3, 4, 5, 6,}
参考答案:ACD
切片赋值时,最后一个元素后面如果有逗号则“}”可以换行或者不换行,否则”}“必须和最后一个元素保持在同一行。
55. 【初级】关于变量的自增和自减操作,下面语句正确的是()
A. i := 1;i++
B. i := 1;j = i++
C. i := 1;++i
D. i := 1;i--
参考答案:AD
Go目前只支持后置自增自减运算符,而且不能用于赋值或者作为参数传递给函数。
package main
import "fmt"
func main() {
i:=1;i--
j := i++ //错误
if i++ > 0 { //错误
fmt.Printf("i=%v\n", i++) //错误
}
++i //错误
fmt.Printf("i=%v j=%v\n", i, j)
}
编译报错:
# command-line-arguments
./example.go:7:8: syntax error: unexpected ++ at end of statement
./example.go:8:9: syntax error: unexpected >, expecting {
./example.go:9:25: syntax error: unexpected ++, expecting comma or )
./example.go:11:2: syntax error: unexpected ++, expecting }
57. 【中级】关于函数声明,下面语法错误的是()
A. func f(a, b int) (value int, err error)
B. func f(a int, b int) (value int, err error)
C. func f(a, b int) (value int, error)
D. func f(a int, b int) (int, int, error)
参考答案:C
Go语言的函数返回值,要么全是非命名的返回值,要么全是命名的返回值,不能即有非命名的又有命名的返回值,否则编译会报错:
syntax error: mixed named and unnamed function parameters
58. 【中级】如果Add函数的调用代码为:
func main() {
var a Integer = 1
var b Integer = 2
var i interface{} = &a
sum := i.(*Integer).Add(b)
fmt.Println(sum)
}
则Add函数定义正确的是()
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
对于方法的参数而言,指针类型的参数不能接受值类型的参数,反之亦然,所以BD是错的。而对于结构体的方法而言,不论定义成值方法或者指针方法,都可以同时支持用指针或者非指针实例来调用。(可能是在编译期完成的转换,后续还需要确认)有两种特殊情况只能定义成值方法:
一是接口断言成非指针实例,例如把main函数改为:
func main() {
var a Integer = 1
var b Integer = 2
var c interface{} = a
sum := c.(Integer).Add(b)
fmt.Println(sum)
}
则答案是 A
运行C则编译报错:
./example.go:9:20: cannot call pointer method on c.(Integer)
./example.go:9:20: cannot take the address of c.(Integer)
二是类型强制转换,例如把main函数改为:
func main() {
var a int = 1
var b Integer = 2
sum := Integer(a).Add(b)
fmt.Println(sum)
}
则答案是 A
运行C则同样是编译报错:
./example.go:8:19: cannot call pointer method on Integer(a)
./example.go:8:19: cannot take the address of Integer(a)
72. 【中级】关于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
Fragment是接口所以赋值成指针或者非指针,AC是指针,D是非指针。B编译报错“type GetPodAction is not an expression”
结构体创建实例有两种等价的形式:
1) var g GetPodAction; 2) g := GetPodAction{}
82. 【中级】关于接口,下面说法正确的是()
A. 只要两个接口拥有相同的方法列表(次序不同不要紧),那么它们就是等价的,可以相互赋值
B. 如果接口A的方法列表是接口B的方法列表的子集,那么接口B可以赋值给接口A
C. 接口查询是否成功,要在运行期才能够确定
D. 接口赋值是否可行,要在运行期才能够确定
参考答案:ABC
接口赋值时编译期就可以报错。
验证代码:
package main
import "fmt"
type A interface {
f1()
f2()
f3()
}
type B interface {
f2()
f1()
}
type AImpl struct {
}
func (a AImpl) f1() {
fmt.Printf("call AImpl f1()\n")
}
func (a AImpl) f2() {
fmt.Printf("call AImpl f2()\n")
}
func (a AImpl) f3() {
fmt.Printf("call AImpl f3()\n")
}
func main() {
var a A = AImpl{}
var b B = a
b.f1()
//接口查询,判断b是否实现了接口A
if c, ok := b.(A); ok {
c.f3()
}
}
输出:
call AImpl f1()
call AImpl f3()
83. 【初级】关于channel,下面语法正确的是()
A. var ch chan int
B. ch := make(chan int)
C. <- ch
D. ch <-
参考答案:ABC
85. 【中级】 golang中大多数数据类型都可以转化为有效的JSON文本,下面几种类型除外()
A. 指针
B. channel
C. complex
D. 函数
参考答案:BCD
87. 【初级】 flag是bool型变量,下面if表达式符合编码规范的是()
A. if flag == 1
B. if flag
C. if flag == false
D. if !flag
参考答案:BD
这道题C也是符合规范的,Go的源代码有很多这样的写法,例如:runtime/pprof/internal/profile:
func encodeBoolOpt(b *buffer, tag int, x bool) {
if x == false {
return
}
encodeBool(b, tag, x)
}
88. 【初级】 value是整型变量,下面if表达式符合编码规范的是()
A. if value == 0
B. if value
C. if value != 0
D. if !value
参考答案:AC
BD两项只能是bool变量,否则编译报错:“non-bool value (type int) used as if condition”,“invalid operation: ! int”
91. 【中级】关于slice或map操作,下面正确的是()
A.
var s []int
s = append(s,1)
B.
var m map[string]int
m["one"] = 1
C.
var s []int
s = make([]int, 0)
s = append(s,1)
D.
var m map[string]int
m = make(map[string]int)
m["one"] = 1
参考答案:ACD
slice和map在插入数据之前都需要分配内存,而append函数内置有内存分配操作,所以在调用append之前可以不用make切片。
93. 【中级】关于channel的特性,下面说法正确的是()
A. 给一个 nil channel 发送数据,造成永远阻塞
B. 从一个 nil channel 接收数据,造成永远阻塞
C. 给一个已经关闭的 channel 发送数据,引起 panic
D. 从一个已经关闭的 channel 接收数据,如果缓冲区中为空,则返回一个零值
参考答案:ABCD
这道题AB两个选项应该是适用于Go的早期版本,在Go1.13.8里面,AB直接报fatal error然后退出。C,D是正确的。
下面是一段能正常运行的代码:
func main() {
ch := make(chan bool)
go func(ch chan bool) {
time.Sleep(1 * time.Second)
b := <-ch
fmt.Printf("b=%v\n", b)
}(ch)
ch <- true
fmt.Printf("exit\n")
}
b=true
exit
按照AB说法,把"ch := make(chan bool)"改成:
func main() {
var ch chan bool
go func(ch chan bool) {
time.Sleep(1 * time.Second)
b := <-ch
fmt.Printf("b=%v\n", b)
}(ch)
ch <- true
fmt.Printf("exit\n")
}
报错退出:
fatal error: all goroutines are asleep - deadlock!
goroutine 1 [chan send (nil chan)]:
main.main()
/home/zhoupeng/go-test/src/tutorial/example.go:15 +0x5b
goroutine 6 [chan receive (nil chan)]:
main.main.func1(0x0)
/home/zhoupeng/go-test/src/tutorial/example.go:12 +0x4b
created by main.main
/home/zhoupeng/go-test/src/tutorial/example.go:10 +0x42
exit status 2
验证C,在“ch <- true”之前加入“close(ch)”,则报错:“panic: send on closed channel”
func main() {
ch := make(chan bool)
go func(ch chan bool) {
time.Sleep(1 * time.Second)
b := <-ch
fmt.Printf("b=%v\n", b)
}(ch)
close(ch)
ch <- true
fmt.Printf("exit\n")
}
验证D,通道写入true之后关闭通道,等待3秒,协程等待1秒后连读2次通道,第一次读到缓冲区里的“true”,第二次缓冲区为空则读取到布尔变量的零值false。注,数值型变量的零值是0,字符串的零值是“”。
func main() {
ch := make(chan bool, 1)
go func(ch chan bool) {
time.Sleep(1 * time.Second)
b1 := <-ch
fmt.Printf("b1=%v\n", b1)
b2 := <-ch
fmt.Printf("b2=%v\n", b2)
}(ch)
ch <- true
close(ch)
time.Sleep(3 * time.Second)
fmt.Printf("exit\n")
}
b1=true
b2=false
exit
94. 【中级】关于无缓冲和有冲突的channel,下面说法正确的是()
A. 无缓冲的channel是默认的缓冲为1的channel
B. 无缓冲的channel和有缓冲的channel都是同步的
C. 无缓冲的channel和有缓冲的channel都是非同步的
D. 无缓冲的channel是同步的,而有缓冲的channel是非同步的
参考答案:D
无缓冲的channel是默认的缓冲为0的channel,对应代码如“make(chan int, 0)”,0是默认值可以省略。有缓冲的channel是非同步的指的是发送/接收操作只在缓冲区满了才阻塞,否则继续执行后面的代码。
缓存为1的时序验证:
func main() {
ch := make(chan int, 1)
go func(ch chan int) {
time.Sleep(2 * time.Second)
i1 := <-ch
log.Printf("i1=%v\n", i1)
time.Sleep(2 * time.Second)
i2 := <-ch
log.Printf("i2=%v\n", i2)
}(ch)
log.Printf("send 1\n")
ch <- 1
log.Printf("send 2\n")
ch <- 2
log.Printf("main sleep\n")
time.Sleep(3 * time.Second)
log.Printf("exit\n")
}
2020/07/13 14:19:26 send 1
2020/07/13 14:19:26 send 2
2020/07/13 14:19:28 i1=1
2020/07/13 14:19:28 main sleep
2020/07/13 14:19:30 i2=2
2020/07/13 14:19:31 exit
从输出可以看出,缓冲区是一个先进先出的队列,发送的顺序是1,2,接收的顺序也是1,2。运行到send2时缓冲区已满,main函数所在协程阻塞,2秒之后另一个协程从通道读取到第一个值1,缓冲区不再是已满的状态,main函数停止阻塞继续执行后面的代码打印“main sleep”,再过2秒之后另一个协程从通道读取到第二个值2。
如果把上述代码改为非缓冲通道,则输出时序为:
2020/07/13 14:37:15 send 1
2020/07/13 14:37:17 i1=1
2020/07/13 14:37:17 send 2
2020/07/13 14:37:19 i2=2
2020/07/13 14:37:19 main sleep
2020/07/13 14:37:22 exit
send1之后就会阻塞,2秒之后等另一个协程读取到第一个值1之后,main再发送send 2,发了之后再阻塞 ,2秒之后等另一个协程读取到第二个值2之后,main解除阻塞。
95. 【中级】关于异常的触发,下面说法正确的是()
A. 空指针解析
B. 下标越界
C. 除数为0
D. 调用panic函数
参考答案:ABCD
96. 【中级】关于cap函数的适用类型,下面说法正确的是()
A. array
B. slice
C. map
D. channel
参考答案:ABD
func main(){
var a [3]int
var sl = make([]int, 1, 5)
var m = make(map[int]int, 100)
var ch = make(chan int, 10)
log.Printf("%d\n",cap(a))
log.Printf("%d\n",cap(sl))
log.Printf("%d\n",cap(m))
log.Printf("%d\n",cap(ch))
}
有疑问加站长微信联系(非本文作者)