1、结构体类型是值类型,在方法调用中,遵守值类型的传递机制,是值拷贝传递方式。
2、如果程序员希望在方法中,修改结构体的值,可以通过结构体指针的方式来处理。
3、Golang中的方法是作用在指定的数据类型上的(即:和指定的数据类型绑定),因此自定义类型,都可以有方法,而不仅仅是struct,比如int,float32等都可以有方法。



报错表明不能给int、float32这种non-local type人为添加方法,否则无法执行。我们只需把int类型换成别名比如myint,系统就认为是自定义类型,那么这样就可以执行了,如下所示:



4、方法的调用范围控制的规则,和函数一样,方法名首字母小写,只能在本包访问;方法名首字母大写,可以在本包和其他包访问。
5、如果一个类型实现了String()的这个方法,那么fmt.Println默认会调用这个变量String()进行输出。
有示例如下:

这里给Student结构体定义了一个String()方法,这会影响到println(结构体实例的输出)。此外,要介绍下Printf和Sprintf的区别:
Printf : 只可以打印出格式化的字符串,可以输出字符串类型的变量,不可以输出整形变量和整形。
Sprintf:用传入的格式化规则符将传入的变量格式化,(终端中不会有显示),返回为 格式化后的字符串。
下面我们执行以下代码:

发现输出为:

说明在执行fmt.Println(student)时,调用了我们自己定义的String()方法,故有了上面的输出。若我们将String()方法注释掉,如下图:

发现输出为:

这里因为我们注释掉了String(),故调用的是原来的fmt.Println()。
6、方法执行时编译器的优化
如下图所示,我们给Student结构体定义了一个edit()的方法,定义中调用它的对象是Student类型,因此main函数中,我们用的student.edit()。

输出如下:

毫无疑问,由于edit()方法是值传递,edit()方法内部给Student对象的age重新复制未能生效。而当我们对上面代码做如下修改后:

这里我们方法接收的对象是*Student,是一个指针,由此可推断这个引用传递的方法执行后可以让Student对象中的age变为40。而我们在main()函数中的调用依旧是student.edit(),此时还能输出我们想要的值吗?

答案是肯定的。其实这里,编译器在底层做了优化,按照最科学的写法,应该是需要这要调用的:

因为edit()方法的调用对象是*Student,我们本应传入一个Student对象的指针即(&student)进去,但是由于编译器做了语法糖优化,不用传入指针变量也能被识别。同理,如果edit()方法传值,我们在main()函数中却用的指针调用,也是可以被识别的。只不过最终Student对象中的age值能否被修改,取决于edit()方法是传值还是传引用,而与你在main()函数中调用时传入的是何种参数无关。
网友评论