Golang Go语言中一个意外的接口方法的非预期输出,你们能答对吗?

Golang Go语言中一个意外的接口方法的非预期输出,你们能答对吗?

猜猜会输出什么?

如果有大佬答对了求解释,非常感谢!

package main

import( “fmt” “encoding/json” )

type a []int

func main(){ b := &a{0} fmt.Printf("%v\n",*b) b.Scan() fmt.Printf("%v\n",*b) b.Scan2() fmt.Printf("%v\n",*b)

}

func (i *a) Scan(){ i = &a{1} }

func (i *a) Scan2(){ json.Unmarshal([]byte{’[’,‘2’,’]’},i) }


更多关于Golang Go语言中一个意外的接口方法的非预期输出,你们能答对吗?的实战教程也可以访问 https://www.itying.com/category-94-b0.html

11 回复

golang 只有值传递,指针在这里也无关紧要。
重点是你要搞清楚 map slice chan 在内存中存储的方式。
你用 gdb 单步看看 b 的地址就明白了。

更多关于Golang Go语言中一个意外的接口方法的非预期输出,你们能答对吗?的实战系列教程也可以访问 https://www.itying.com/category-94-b0.html


Scan: 指针也是值类型,改变的只是当前作用域i的存的指针值,不是改的i指针指向的内存
Scan2: json.Unmarshal里面实际是解引用改变原地址的值,等同于*i = a{2}

感谢两位大佬的点拨,一针见血啊!在内存中指针被复制了一份修改并未反应回原指针,导致值未改变。再次感谢大佬!!困扰了我一晚上的问题,我果然还是太弱鸡了😭

我认为你这是误导。和指针没有关系,是 slice 在内存中的存储方式导致的。去掉所有的&和*这段代码还是一样的结果。但把[]int 换成 struct 马上就能得到所谓的预期输出。

啥意思,去掉&和*当然一样了,除非手动解引用。
struct 的.就是解引用

其实楼主没讲清楚他的问题,我估计是说为啥两个 Scan 一个不能改变入参另一个不能改变,2 楼讲的内容应该更能回应楼主的疑惑。核心就在于 i = &a{1} 这个地方 i 本身被重新赋值,这个赋值不影响它指向的那块内存内容。

slice 是一种特殊的 struct,传参的场景可以当 struct 一样理解。

请问你知道 *i = a{2} 和 i = &a{2} 的区别吗?

虽然我非常抵触使用引用来描述一个值这种说法(因为常常引起误解),
这里为了和大家保持一致,暂时还是使用此说法。

当修改一个指针参数所指的值的时候,此指针可以被看做是一个引用值。
但是当此指针参数本身被修改的时候,此此指针应该被看做是一个非引用值。

简单说来,在一个函数内部对一个形参本身进行的任何修改都不会体现到相应传递的实参上。
因为此形参只不过是相应实参的一个副本。

一楼没说到点子上,二楼讲对了

对不起,我愚蠢了,完全是半桶水瞎晃悠,慎之戒之。



在Go语言中,接口方法的非预期输出通常与接口的动态类型和值接收者/指针接收者的区别有关。这是一个常见的陷阱,尤其对于初学者来说。

首先,要明确接口在Go中是一个抽象类型,它规定了对象的行为。当一个值被赋给接口变量时,会发生隐式类型转换,接口变量会保存该值的类型和值(或指针)。调用接口方法时,会根据保存的具体值来动态决定调用哪个方法。

非预期输出可能源于以下几个方面:

  1. 值接收者与指针接收者:如果接口保存的是值的副本,而方法是通过指针接收者定义的,那么在通过接口调用该方法时,如果该方法试图修改接收者的状态,这些修改将不会反映到原始变量上,因为接口内部保存的是值的副本。

  2. 接口变量的nil检查:有时接口变量可能看起来非nil(因为它保存了一个类型的零值),但实际上其动态类型为nil,这可能导致在调用方法时发生panic。

  3. 类型断言失败:如果错误地假设了接口变量保存的具体类型,类型断言可能会失败,导致非预期的行为。

解决这类问题通常需要仔细检查接口变量的赋值过程、方法接收者的类型(值或指针),以及任何可能的类型断言或类型转换。使用fmt.Printf("%T\n", variable)可以帮助确定接口变量当前保存的具体类型。

总之,理解和调试接口的非预期输出需要细心检查类型系统和接口的使用方式。

回到顶部