上一章:Chapter010 golang中struct结构体
下一章:Chapter012 golang面向对象编程应用实例
一、简单快速入门
1、golang中方法是作用在指定数据类型上的(即:和指定的数据类型绑定),因此,自定义类型都可以有方法,而不仅仅是struct
2、方法申明和调用
func (receive type) methodName (参数列表) (返回列表){
方法体
return 返回值列表
}
(1)参数列表:表示方法输入
(2)receive type:表示这个方法和type这个类型进行绑定,或者说该方法作用于type类型。type可以是结构体,也可以是其他的自定义类型。
(3)receiver :就是type类型的一个变量(实例),比如Person结构体的一个变量(实例)
(4)返回值列表:表示返回的值,可以多个
(5)方法主体:表示为了实现某一功能代码块
(6)return 语句不是必须的(但是有返回值列表或者返回值就必须有)
3、举例:
type A struct{
Num int
}
func(a A)test(){
fmt.Println(a.num)
}
3、对上面语法的说明
(1)func(a A) test(){}表示A结构体有一方法,方法名为test
(2)(aA)体现test方法是和A绑定的
package main
import (
"fmt"
_ "fmt"
)
type Person struct {
Name string
}
//给A类型绑定一个方法 ,Person的变量名为p
func (p Person)test() {
fmt.Println("test()",p.Name)
}
func main() {
var p1 Person
p1.test() //调用方法,这个时候就会把这里的p1传给上面的方法为p
p1.Name = "tom"
p1.test() //调用方法,这个时候就会把这里的p1传给上面的方法为p
}
(3)对上面代码说明
1)test方法和Person类型绑定
2)test方法只能通过Person类型的变量来调用,而不能直接调用,也不能使用其他类型的变量调用 ,即不能直接test()和p1.test()
3)func(p Person) test() {}… p表示哪个Person调用,这个p就是它的副本,这点和函数传参非常相似
package main
import (
"fmt"
_ "fmt"
)
type Person struct {
Name string
}
//给A类型绑定一个方法 ,Person的变量名为p
func (p Person)test() {
p.Name = "jack"
fmt.Println("test()",p.Name)
}
func main() {
var p1 Person
p1.test() //调用方法,这个时候就会把这里的p1传给上面的方法为p
p1.Name = "tom"
p1.test() //调用方法,这个时候就会把这里的p1传给上面的方法为p
fmt.Println("test()",p1.Name)
}
即:
4)p这个形参名,有程序员指定,不是固定
二、方法举例
package main
import (
"fmt"
_ "fmt"
)
type Person struct {
Name string
}
func (p Person) speak() {
fmt.Print(p.Name," is a good person\n")
}
func (p Person) jisuan() {
res :=0
for i:= 1;i<100;i++{
res +=i
}
fmt.Print(res)
}
func (p Person) jisuan2(n int) {
res :=0
for i:= 1;i<n;i++{
res +=i
}
fmt.Print(res,"\n")
}
func (p Person) getSum(n1 int,n2 int) int {
res := n1+n2
return res
}
func main() {
person :=Person{"tom"}
person.speak()
person.jisuan()
person.jisuan2(100)
res := person.getSum(10,20)
fmt.Print(res,"\n")
}
三、方法的调用和传参机制原理
1、在通过一个变量去调用方法时,其调用机制和函数是一样的
2、不一样的地方是,变量调用方法时,该变量本身也会作为一个参数传递到方法(如果变量是值类型,进行值拷贝,是引用类型,进行地址拷贝)
3、案例演示
求周长和面积:
package main
import (
"fmt"
_ "fmt"
)
type Circle struct {
radius float64
}
func (c Circle) area() float64 {
return 3.14 * c.radius * c.radius
}
func (c Circle) lens() float64 {
return 2*3.14*c.radius
}
//为了提高效率,通常和结构体指针相绑定 **********************此时就是引用类型了
func (c *Circle) area2() float64 {
return 3.14 * (*c).radius * (*c).radius //等价于c.radius
}
func (c *Circle) lens2() float64 {
return 2 * 3.14 * (*c).radius //等价于c.radius
}
func main() {
var circle Circle
circle.radius = 4.0
area := circle.area()
lens := circle.lens()
fmt.Print("面积是:",area,"\n","周长是:",lens,"\n")
area2 :=(&circle).area2() //等价于circle.area2()
lens2 :=(&circle).lens2() //等价于circle.lens2()
fmt.Print("2: 面积是:",area2,"\n","周长是:",lens2)
}
四、方法的注意事项和细节
1、结构体是值类型,在方法调用时,遵守值类型的传递机制,是值拷贝
2、如程序员希望在方法中,修改结构体变量的值,可以通过结构体指针的方式来修改
3、Golang中的方法作用在指定的数据类型上的(即:和指定的数据类型绑定),因此自定义类型,都可以有方法,而不仅仅是struct,比如int、float32等都可以有方法
例如:
package main
import (
"fmt"
_ "fmt"
)
type integer int
func (i integer) printi() {
fmt.Println("i=",i)
}
func main() {
var i integer = 10
i.printi()
}
4、方法的访问范围控制的规则,和函数一样。方法名首字母小写,只能在本地访问,方法首字母大写,可以在本包和其他包访问
5、如果一个类型实现了String()这个方法,那么fmt.Println就会默认调用这个变量的String()进行输出(应用:输出日志)
package main
import (
"fmt"
_ "fmt"
)
type Student struct {
Name string
Age int
}
func (stu *Student) String() string { //**************************
str := fmt.Sprintf("Name = [%v],Age = [%v]",stu.Name,stu.Age)
return str
}
func main() {
var stu Student
stu.Name = "tom"
stu.Age = 10
fmt.Println(&stu) //******************************************
}
五、方法和函数的区别
1、调用不一样
(1)函数的调用:函数名(实参列表)
(2)方法的调用:变量 方法名(实参列表)
2、对于普通函数:接受者为值类型时,不能将指针类型的数据直接传递,反之亦然
3、对于方法(如struct的方法)接受者为值类型时,可以直接使用指针类型的变量调用方法,反过来同样也可以
六、总结
不管调用如何,真正决定是值拷贝还是地址拷贝,看这个方法是和那个类型绑定