本题选择:A
在golang中,其实所有的都是值传递的 首先
func main() {
var num int = 5
fmt.Printf("%d\n", num)
changeint(num)
fmt.Printf("%d\n", num)
}
func changeint(num int) {
num = 10
fmt.Printf("%d\n", num)
}
5
10
5
很容易看出来,函数对于原本的数据并没有做修改
func main() {
slice := []int{1, 2, 3, 4, 5}
fmt.Printf("切片:%v\n", slice)
setSliceNil(slice)
fmt.Printf("切片:%v\n", slice)
}
func setSliceNil(slice []int) {
slice = nil
fmt.Printf("切片:%v\n", slice)
}
切片:[1 2 3 4 5]
切片:[]
切片:[1 2 3 4 5]
同样 函数并没有影响原本的切片的值
但是下面的代码就很令人费解了~
func main() {
slice := []int{1, 2, 3, 4, 5}
fmt.Printf("切片:%v\n", slice)
changeSlice(slice)
fmt.Printf("切片:%v\n", slice)
}
func changeSlice(slice []int) {
slice[2] = 10
fmt.Printf("切片:%v\n", slice)
}
切片:[1 2 3 4 5]
切片:[1 2 10 4 5]
切片:[1 2 10 4 5]
很奇怪,不是值传递吗?怎么被修改了啊?
我开始也这样觉着的,可恶!!
引用网络文章
Go 语言里的引用类型有如下几个:切片、映射、通道、接口和函数类型。当声明上述类型的变量时,创建的变量被称作标头(header)值。从技术细节上说,字符串也是一种引用类型。每个引用类型创建的标头值是包含一个指向底层数据结构的指针。因为标头值是为复制而设计的,所以永远不需要共享一个引用类型的值。标头值里包含一个指针,因此通过复制来传递一个引用类型的值的副本,本质上就是在共享底层数据结构。
总而言之,引用类型在函数传递的时候,是值传递,只不过这里的“值”指的是标头值。
这个解释有点抽象,我也不太明白。我们换一个好理解一点的2
func main() {
i:=10
ip:=&i
fmt.Printf(“原始指针的内存地址是:%p\n”,&ip)
modify(ip)
fmt.Println(“int值被修改了,新值为:”,i)
}
func modify(ip *int){
fmt.Printf(“函数里接收到的指针的内存地址是:%p\n”,&ip)
*ip=1
原始指针的内存地址是:0xc42000c028
函数里接收到的指针的内存地址是:0xc42000c038
int值被修改了,新值为: 1
}
1.我们声明了一个变量i,值为10,它的内存存放地址是0xc420018070,通过这个内存地址,我们可以找到变量i,这个内存地址也就是变量i的指针ip。
2.指针ip也是一个指针类型的变量,它也需要内存存放它,它的内存地址是多少呢?是0xc42000c028。 在我们传递指针变量ip给modify函数的时候,是该指针变量的拷贝,所以新拷贝的指针变量ip,它的内存地址已经变了,是新的0xc42000c038。
3.不管是0xc42000c028还是0xc42000c038,我们都可以称之为指针的指针,他们指向同一个指针0xc420018070,这个0xc420018070又指向变量i,这也就是为什么我们可以修改变量i的值。
如果前后都是0xc42000c028(地址没变),那么就是引用传递。
再举个Map的例子
func main() {
persons:=make(map[string]int)
persons[“张三”]=19
mp:=&persons
fmt.Printf(“原始map的内存地址是:%p\n”,mp)
modify(persons)
fmt.Println(“map值被修改了,新值为:”,persons)
}
func modify(p map[string]int){
fmt.Printf(“函数里接收到map的内存地址是:%p\n”,&p)
p[“张三”]=20
}
原始map的内存地址是:0xc42000c028
函数里接收到map的内存地址是:0xc42000c038
map值被修改了,新值为: map[张三:20]
两个内存地址是不一样的,所以这又是一个值传递(值的拷贝)
传入的应该也是一个指针类型的参数
这题我的思路:首先 作为map的key一定是不能有重复的,那如何做到不能重复呢?那就是做比较
而BCD都不可比较,传入的都是地址,理论上来说是不能做键的...
golang的recover机制要求必须在defer的函数里才能执行catch panic
Panic 是一个内建函数,可以中断原有的控制流程,进入一个令人恐慌的流程中。当函数F调用panic,函数F的执行被中 断,但是F中的延迟函数会正常执行,然后F返回到调用它的地方。在调用的地方,F的行为就像调用了panic。这一 过程继续向上,直到发生panic的goroutine中所有调用的函数返回,此时程序退出。恐慌可以直接调用panic产 生。也可以由运行时错误产生,例如访问越界的数组。 Recover 是一个内建的函数,可以让进入令人恐慌的流程中的goroutine恢复过来。recover仅在延迟函数中有效。在正常 的执行过程中,调用recover会返回nil,并且没有其它任何效果。如果当前的goroutine陷入恐慌,调用 recover可以捕获到panic的输入值,并且恢复正常的执行。
D选项嵌套崩溃
选D没啥讲的,前面那个代码差不多解释了这个问题
[图片上传中...(image.png-9e52ab-1624981995115-0)]
这题有俩坑:
先解释aa() defer的底层是栈 先进后出 所以最后答案是210 从cd里面选择
首先,在bb()中只有在i=3的时候才会跳出,所以选D
然后继续从栈中获取defer fun()拿到对应的i值
少加...(三个点)
没啥说的,拿的都是map的头地址
D:
go func()是随机调用的,如果chan已经关闭 但是往里面发送内容就会panic
原来函数也可以作为参数传递呀!~!
type testInt func(int) bool // 声明了一个函数类型
func isOdd(integer int) bool {
if integer%2 == 0 {
return false
}
return true
}
func isEven(integer int) bool {
if integer%2==0 {
return true
}
return false
}
// 声明的函数类型在这个地方当做了一个参数
func filter(slice []int,f testInt) []int {
var result []int
for _,value := range slice{
if f(value){
result = append(result,value)
}
}
return result
}
func main() {
slice := []int {1,2,3,4,5,6}
fmt.Println(slice)
odd:=filter(slice,isOdd)
fmt.Println(odd)
even:=filter(slice,isEven)
fmt.Println(even)
}
[1 2 3 4 5 6]
[1 3 5]
[2 4 6]