方法
什么是方法?
方法其实就是一个函数,在 func
这个关键字和方法名中间加入了一个特殊的接收器类型。接收器可以是结构体类型或者是非结构体类型。接收器是可以在方法的内部访问的。
下面就是创建一个方法的语法。
package main
import "fmt"
type Person2 struct {
Id int
Name string
Sex string
}
//定义一个方法
// 接收器 方法名
func (p Person2)PrintName() {
// 在方法内可以使用p
fmt.Println(p.Name)
}
func main() {
per:=Person2{} // 相当于实例化对象
per.Name = "哎咿呀" // 对象的改值
per.PrintName() // 调用方法
per1 := Person2{22,"李逵","男"}
per1.PrintName() // 谁调用打印谁的
}
-------------------------------------------
哎咿呀
李逵
方法的使用二
package main
import "fmt"
type Person2 struct {
Id int
Name string
Sex string
}
//定义一个方法
// 接收器 方法名
func (p Person2) PrintName() {
// 在方法内可以使用p
fmt.Println(p.Name)
}
// 定义一个有参方法
func (p Person2) ChangeName(name string) {
p.Name = name
fmt.Println(p)
}
func main() {
per := Person2{} // 相当于实例化对象
per.Name = "哎咿呀" // 对象的改值
per.PrintName() // 调用方法
per1 := Person2{22, "李逵", "男"}
per1.ChangeName("李二狗") // 谁调用打印谁的
fmt.Println(per1)
}
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-ZyOb9nje-1614135406446)(https://gitee.com/A1L19/PicGO/raw/master/PicGo/image-20210223220526436.png)]
值接收器和指针接收器
package main
import "fmt"
type Person2 struct {
Id int
Name string
Sex string
}
// 定义一个有参方法
func (p *Person2) ChangeSex(sex string) {
p.Sex = sex
fmt.Println("指针已处理",p.Sex) // 推荐使用这种自动帮你处理了
fmt.Println("指针未处理",(*p).Sex) // 两种方法都可以
}
func main() {
per1 := Person2{22, "李逵", "男"}
per1.ChangeSex("狗") // 谁调用打印谁的
fmt.Println(per1)
}
--------------------------------------------------------------------
指针已处理 狗
指针未处理 狗
{22 李逵 狗} //z指针传递的时候原来的结构体也发生了修改
那么什么时候使用指针接收器,什么时候使用值接收器?
一般来说,指针接收器可以使用在:对方法内部的接收器所做的改变应该对调用者可见时。
指针接收器也可以被使用在如下场景:当拷贝一个结构体的代价过于昂贵时(占用内存过多时)。考虑下一个结构体有很多的字段。在方法内使用这个结构体做为值接收器需要拷贝整个结构体,这是很昂贵的。在这种情况下使用指针接收器,结构体不会被拷贝,只会传递一个指针到方法内部使用。
在其他的所有情况,值接收器都可以被使用。
简单来说就是,想改原来的值就用指针,不想改就用值,指针用的多
匿名字段方法
属于结构体的匿名字段的方法可以被直接调用,就好像这些方法是属于定义了匿名字段的结构体一样。
package main
import "fmt"
// 匿名字段的方法
type Hobby struct {
Id int
Name string
}
type Person struct {
Id int
Name string
Sex string
Hobby //匿名字段
}
func (p Person) PrintName(){
fmt.Println(p.Name)
}
func (h Hobby) HobbyName(){
fmt.Println(h.Name)
}
func (h Hobby) PrintName(){
fmt.Println(h.Name)
}
func main() {
pe := Person{Name: "孙悟空",Hobby:Hobby{1,"棒子"}}
pe.HobbyName() //由于Hobby是个匿名字段,所以方法也提升了,如果方法名重了,优先用结构体自己的
pe.PrintName()
}
---------------------------------------------------------------------
棒子
孙悟空
在方法中使用值接收器 与 在函数中使用值参数
和值参数相类似,函数使用指针参数只接受指针,而使用指针接收器的方法可以使用值接收器和指针接收器。
package main
import "fmt"
// 在方法中使用指针接收器 与 在函数中使用指针参数
type Name struct {
Id int
Name string
Sex string
}
// 在方法中使用值接收器
func (n Name) PrintName() {
fmt.Println(n.Name)
}
// 在函数中使用值参数,只能传值
func FPrintName(p Name) {
fmt.Println(p.Name)
}
func main() {
n1 := &Name{Name: "孙悟空"}
n2 := Name{Name: "猪八戒"}
n1.PrintName()
n2.PrintName()
FPrintName(*n1)
FPrintName(n2)
}
// 值接收器:可以用值来调用也可以用指针来调用
// 函数的值参数,只能传值
----------------------------------------------------------
孙悟空
猪八戒
孙悟空
猪八戒
改值
func (n Name)ChangeName(name string) {
n.Name=name
fmt.Println(n.Name)
}
func main() {
n1 := &Name{Name: "孙悟空"}
n2 := Name{Name: "猪八戒"}
n1.ChangeName("噢哈哈")
fmt.Println(n1)
n2.ChangeName("嘿哈哈")
fmt.Println(n2)
}
-------------------------------------------------
噢哈哈
&{0 孙悟空 } // 虽然是指针类型但是复制了一份
嘿哈哈
{0 猪八戒 }
在方法中使用指针接收器 与 在函数中使用指针参数
总结:不管是值类型接收器还是指针类型接收器,都可以用值来调用,或者指针来调用
指针类型接收器修改的就是原值,值类型都会拷贝一份,他只和接收器类型有关,也就是接收器类型是指针改的就是原值
接收器是值类型改的就是新的
package main
import "fmt"
// 在方法中使用指针接收器 与 在函数中使用指针参数
type Name struct {
Id int
Name string
Sex string
}
// 在方法中使用值接收器
func (n *Name) PrintName() {
fmt.Println(n.Name)
}
func (n *Name)ChangeName(name string) {
n.Name=name
fmt.Println(n.Name)
}
// 在函数中使用指针,只能传指针
func FPrintName(p *Name) {
fmt.Println(p.Name)
}
func main() {
n1 := &Name{Name: "孙悟空"}
n2 := Name{Name: "猪八戒"}
n1.PrintName()
n2.PrintName()
FPrintName(n1)
FPrintName(&n2)
n1.ChangeName("噢哈哈")
fmt.Println(n1)
n2.ChangeName("嘿哈哈")
fmt.Println(n2)
}
// 总结:不管是值类型接收器还是指针类型接收器,都可以用值来调用,或者指针来调用
// 指针类型接收器修改的就是原值,值类型都会拷贝一份,他只和接收器类型有关,也就是接收器类型是指针改的就是原值
// 接收器是值类型改的就是新的
非构体方法
package main
import "fmt"
// 在int上绑定一个add方法(不允许)
//func (i int)add() {
// i = i+1
// i ++
// i+=1
//}
//
//但是可以在自定义的类型上绑定方法
type sint int
func (i *sint) add() {
*i++
*i += 1
*i = *i + 1
}
func main() {
var a sint = 10
fmt.Println(a)
a.add()
fmt.Println(a)
}
---------------------------------------------
10
13