方法:
创建格式:
func (接受者变量 接受者) 方法名 (参数列表) (返回值列表){}
调用:
对象.方法名
方法是值拷贝,在方法中修改是不会影响原数据的
type Student struct {
name string
}
// 创建了一个StudentMethod方法,绑定了Student,可以称为Student的方法
// s是Student的变量,可以用来调用Student的成员
func (s Student) StudentMethod() {
fmt.Println("我是Student的方法")
fmt.Println("StudentMethod修改前:", s.name)
s.name = "韩信"
fmt.Println("StudentMethod修改后:", s.name)
}
func main() {
stu := Student{"itzhuzhu"}
stu.StudentMethod() // 调用方法
fmt.Println("main运行修改后:", stu.name)
}
输出:
我是Student的方法
StudentMethod修改前: itzhuzhu
StudentMethod修改后: 韩信
main运行修改后: itzhuzhu
三种不同调用的方式
type Student struct {
name string
age int
}
func (s *Student) StudentMethod() {
fmt.Println(*s)
}
func main() {
// 普通方式调用
s := Student{name: "韩信", age: 99}
s.StudentMethod()
// 方法值调用
x := s.StudentMethod
x()
// 方法表达式调用,要和方法对象的类型保持一致,方法对象是指针类型,这里也要加上*
y := (*Student).StudentMethod
//y2:=Student.StudentMethod 不可用
//y2(&s)
y(&s)
}
带参数和返回值的方法:返回x+y的和
type Count struct{}
func (c *Count) count(x, y int) int {
return x + y
}
func main() {
c := Count{}
c.count(100, 200)
}
变量调用方法时,该变量也会作为一个参数传递到方法(如果是引用类型,则进行地址拷贝,否则为值拷贝)
type Test struct{}
func (t Test) TestMethod(x, y int) int {
/*
这里的变量t和main方法中的变量t,不是同一个t,因为是值拷贝,
所以main栈调用TestMethod方法时,会将main栈的t拷贝一份到TestMethod方法中,
如果是指针,那么拷贝的是内存地址
*/
fmt.Printf("TestMethod方法中的t:%p", &t)
return x + y
}
func main() {
t := Test{}
fmt.Printf("main函数中的t:%p\n", &t)
testMethod := t.TestMethod(1, 2)
fmt.Println(testMethod)
}
输出:
main函数中的t:0x102f1bfa8
TestMethod方法中的t:0x102f1bfa83
指针类型使用方法
type Test struct {
num int
}
func (t *Test) TestMethod(x, y int) int {
t.num = 2
fmt.Println("TestMethod修改为2:", t.num)
return x + y
}
func main() {
t := Test{}
t.num = 1
fmt.Println("传递TestMethod方法前:", t.num)
testMethod := (&t).TestMethod(1, 2)
fmt.Println("调用完方法后:", t.num)
fmt.Println(&t)
// 也可以简写成以下模式,因为编译器在底层做了优化,在编译时会自动加上(&)
testMethod2 := t.TestMethod(1, 2)
fmt.Println(testMethod)
fmt.Println(testMethod2)
}
输出:
传递TestMethod方法前: 1
TestMethod修改为2: 2
调用完方法后: 2
&{2}
TestMethod修改为2: 2
3
3
方法可以作用在指定的数据类型上,所有的自定义类型都可以有方法
type integer int
func (i integer) print() {
fmt.Println("print方法:", i)
}
func (i *integer) change() {
fmt.Println("change方法", *i)
}
func main() {
var i integer = 10
i.print()
i.change()
fmt.Println("main方法:", i)
}
输出:
print方法: 10
change方法 10
main方法: 10
如果一个类型实现了String()方法,那么输出时会默认调用String()
type Student struct {
name string
age int
}
// 改成AAA就不会默认调用了
func (stu *Student) String() string {
return "String方法执行"
}
func main() {
stu := Student{"不知火舞", 99}
fmt.Println(&stu)
}
输出:
String方法执行
方法重写:
方法重写是父类中的方法与子类方法重名的问题,默认调用子类的方法,如果需要使用父类的,需要使用子类.父类.方法名
调用
// 父类
type Person struct {
name string
age int
}
func (p *Person) Show() {
fmt.Println("我是Person的show方法")
}
// 子类
type Student struct {
Person
}
func (s *Student) Show() {
fmt.Println("我是Student的show方法")
}
func main() {
s := Student{Person{
name: "韩信",
age: 99,
}}
s.Show() // 优先使用自己的
//如果需要使用父类的,需要明示使用父类调用
s.Person.Show()
}
输出:
我是Student的show方法
我是Person的show方法
方法和函数的区别:
- 方法有接受者,而函数无接受者
- 函数不可以重名,而方法可以重名(绑定不同数据类型)
- 调用方式不一样
函数:函数名(实参列表)
方法:变量.方法名(实参列表)
- 函数:
- 参数为值类型时不能传递指针类型,为指针类型时不能传递值类型。
- 方法是值类型还是指针类型,都可以使用值或指针调用
注意:判断方法是否为指针类型,不应该从调用者出发 s.Test03(),是由方法关联类型决定的(h Hero) test03()、(h *Hero) test04()
type Hero struct {
name string
}
// 值类型函数
func test01(h Hero) {
fmt.Println("test01:", h.name) //不知火舞
}
// 指针类型函数
func test02(h *Hero) {
fmt.Println("test02:", h.name) //不知火舞
}
// 普通方法
func (h Hero) test03() {
h.name = "干将莫邪" //值拷贝,不影响主函数Name
fmt.Println("test03:", h.name) // 干将莫邪
}
// 指针类型方法
func (h *Hero) test04() {
h.name = "干将莫邪" // 指针会直接修改原数据
fmt.Println("test04:", h.name) // 干将莫邪
}
func main() {
h := Hero{"不知火舞"}
//test01(&h) // 无法将 '&h' (类型 *Hero) 用作类型 Hero
test01(h)
//test02(h) // 无法将 'h' (类型 Hero) 用作类型 *Hero
test02(&h)
(&h).test03() // 看似是传递指针,实际上还是传入值类型,但是本质仍然是地址拷贝,面试的时候会留坑让误以为传递的是指针,联想到是指针类型的方法
fmt.Println("main调用test03后", h.name)
(&h).test04()
fmt.Println("main调用test04后", h.name) // 干将莫邪
h.test04() // 等价 (&p).test04 ,
fmt.Println("main调用test04后", h.name) // 干将莫邪
}
输出:
test01: 不知火舞
test02: 不知火舞
test03: 干将莫邪
main调用test03后 不知火舞
test04: 干将莫邪
main调用test04后 干将莫邪
test04: 干将莫邪
main调用test04后 干将莫邪
练习方法:
键盘录入数据,判断是奇数还是偶数
type TestMethod struct{}
func (t *TestMethod) JudgeNumber() {
var num int
fmt.Println("请输入一个整数:")
fmt.Scan(&num)
if num%2 == 0 {
fmt.Println(num, "是偶数")
} else {
fmt.Println(num, "是奇数")
}
}
func main() {
t := TestMethod{}
t.JudgeNumber()
}