Golang中的方法是作用在指定的数据类型上的,因此自定义类型都可以有方法。
方法定义
func (recevier type) methodName (参数列表) (返回值列表) {
方法体
return 返回值
}
基本申明和调用
type A struct {
Num int
}
func (a A) test() {
fmt.Println(a.Num)
}
说明:func (a A) test() 表示结构体A有一个test的方法
package main
import "fmt"
type Person struct {
Name string
Age int
}
// 定义一个方法
func (p Person) Talk() {
fmt.Println(p.Name)
}
func main() {
var person1 = Person{
Name: "宋江",
Age: 20,
}
person1.Talk()
}
方法中指针的使用
package main
import "fmt"
type Person struct {
Name string
Age int
}
// 给Person结构体定义一个方法
func (p *Person) Talk() { // *Person 表示传递参数为指针
p.Name = "卢俊义"
// 指针标准写法
fmt.Println("Talk(),Name=", (*p).Name)
// 省略写法
fmt.Println("Talk(),Name=", p.Name)
}
func main() {
var person1 = Person{
Name: "宋江",
Age: 20,
}
person1.Talk()
fmt.Println("main(),Name=", person1.Name) // 指针修改了值,所以输出:卢俊义
}
方法中使用内置类型
package main
import "fmt"
type integer int // 给内置类型指定别名
func (i *integer) change() {
*i++ // 这里的*不能省略
}
func main() {
var i integer = 10
i.change()
fmt.Println(i)
}
指针默认调用String()
package main
import "fmt"
type Student struct {
Name string
Age int
}
func (stu *Student) String() string {
s := fmt.Sprintf("Name=[%v], Age=[%v]", stu.Name, stu.Age)
return s
}
func main() {
stu := Student{
Name: "宋江",
Age: 20,
}
fmt.Println(stu)
fmt.Println(&stu) // 指针会自动调用String()
}
方法和函数的不同点
调用方式不同
函数的调用方式:函数名(实参列表)
方法的调用方式:变量.方法名(实参列表)
对于普通函数,接受者为值类型时不能传递指针类型;接受者为指针时不能传递值类型
package main
import "fmt"
type Student struct {
Name string
}
// 定义接受值类型函数,只能传递值类型
func Speak(stu Student) string {
return stu.Name
}
// 定义接受指针类型函数,只能指针类型
func Speak2(stu *Student) string {
stu.Name = "卢俊义" // 此处为省略写法,标准写法为:(*stu).Name = "卢俊义"
return stu.Name
}
func main() {
stu := Student{
Name: "宋江",
}
fmt.Println(Speak(stu)) // 只能传递值类型
fmt.Println(stu.Name)
fmt.Println(Speak2(&stu)) // 只能传递指针类型
fmt.Println(stu.Name)
}
对于方法(如struct的方法),接受者为值类型时可以用传递指针类型;接受者为指针时也可以传递值类型
package main
import "fmt"
type Student struct {
Name string
}
// Student结构体的方法,值传递可以是值类型,也可以是指针
func (stu Student) Speak() string {
s := fmt.Sprintf("Name=[%v]", stu.Name)
return s
}
// Student结构体的方法,值传递可以是值类型,也可以是指针
func (stu *Student) Speak2() string {
stu.Name = "卢俊义"
s := fmt.Sprintf("Name=[%v]", stu.Name)
return s
}
func main() {
stu := Student{
Name: "宋江",
}
fmt.Println(stu.Speak())
fmt.Println((&stu).Speak()) // 传递指针也可以。此处注意,虽然传递的是指针,但stu.Name并不会改变!!!
fmt.Println(stu.Name)
fmt.Println(stu.Speak2()) // 传递值类型也可以
fmt.Println((&stu).Speak2())
fmt.Println(stu.Name) // 由于执行了Speak2()指针方法,因此Name改为:卢俊义
}
总结
不管调用方式如何,真正决定是指拷贝还是地址拷贝,看这个方法是和哪个类型绑定
如果是和值类型绑定,如:(str Student),则是值拷贝;如:(str *Student),则是地址拷贝
地址拷贝会修改原定义值