方法
golang中的方法是作用在指定的数据类型上的(即和指定的数据类型绑定),因此自定义类型,都可以有方法,而不仅仅是struct
type Person struct {
Name string
Age int
}
//给Person类型绑定一个方法
func (a Person)test(){
fmt.Println(a.Name)
}
func main() {
var a Person
a.Name = "tom"
//调用方法
a.test()
}
- test方法和Person类型绑定
- test方法只能通过Person类型的变量来调用,而不能直接调用,也不能使用其他类型变量调用
- func(p Person)test(){} p表示哪个Person变量调用,这个p就是它的副本,这点和函数传参非常相似
- p这个形参名,有程序员指定,不固定
type Person struct{
Name string
}
//给Person结构体添加speak方法
func (p Person)speak(){
fmt.Println(p.Name,"是一个好人")
}
//传参计算
func (p Person)jisuan(n int ){
res := 0
for i := 1;i <= n;i++{
res += i
}
fmt.Println(res)
}
//传返回值
func (p Person)getsum(n1 int,n2 int)int{
return n1 + n2
}
func main() {
var a Person
a.Name = "jack"
a.speak()
a.jisuan(10)
res := a.getsum(10,20)
fmt.Println(res)
}
-
方法的调用和传参机制
-
在通过一个变量去调用方法时,其调用机制和函数一样
-
不一样的地方是,变量调用方法时,该变量本身也会作为一个参数传递到方法(如果变量是值类型,则进行值拷贝,如果变量是引用类型,则进行地址拷贝)
type Circle struct {
radius float64
}
func (c Circle)area(radius float64)float64 {
area := radius * radius * 3.14
return area
}
func main() {
var b Circle
fmt.Println(b.area(2))
}
- 结构体类型是值类型,在方法调用中,遵守值类型的传递机制,是值拷贝传递方式
- 如果程序员希望在方法中修改结构体变量的值,可以通过结构体指针的方式处理
func (c *Circle)area1()float64{
c.radius = 4
area := c.radius * c.radius * 3.14
return area
}
func main() {
var b Circle
b.radius = 3
fmt.Println(b.area1()) //结果为4为半径的面积
}
- golang中的方法作用在指定的数据类型上的(即:和指定的数据类型绑定),因此自定义类型都可以有方法,而不仅仅是struct,比如int ,float等都可以有方法
type integer int
func (i integer)print() {
fmt.Println(i)
}
//编写一个方法,可以改变i的值
func (i *integer)change(){
*i = *i + 1
}
func main() {
var c integer = 1
c.print()
c.change()
fmt.Println(c)
}
- 方法的访问范围控制的规则和函数一样,方法的首字母小写,只能在本包访问,方法的首字母大写,可以在本包和其他包访问
- 如果一个类型实现了string()这个方法,那么fmt.Println默认会调用这个变量的String()进行输出
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() {
d := Student{
Name: "txy",
Age: 20,
}
fmt.Println(d.string())
}
实例一:编写一个结构体,方法,方法不需要参数,在方法中打印一个5*6的矩形,在main方法中调用该方法
type MethodUtils struct {
}
func (m MethodUtils)print() {
for i := 1;i <= 5;i++{
for j := 1;j <= 6;j++{
fmt.Printf("*")
}
fmt.Printf("\n")
}
}
func main() {
var a MethodUtils
a.print()
}
实例二:编写一个方法,提供m和n两个参数,方法中打印一个m*n的矩形
func (method MethodUtils)print1(n int,m int){
for i := 1;i <= n;i++{
for j := 1;j <= m;j++{
fmt.Print("*")
}
fmt.Println()
}
}
func main() {
var b MethodUtils
b.print1(4,5)
}
实例三:编写一个方法算该矩形面积(可以接收长len和宽width),将其作为方法返回值。在main方法中调用该方法,接收返回的面积值并打印。
func (method MethodUtils)area(len float64,width float64)float64 {
area := len * width
return area
}
func main() {
var c MethodUtils
fmt.Println(c.area(4,5))
}
实例四:编写方法:判断一个数是奇数还是偶数
func (method *MethodUtils) judge(n int) {
if n % 2 == 0{
fmt.Printf("%v是偶数",n)
}else {
fmt.Printf("%v是奇数",n)
}
}
func main() {
var d MethodUtils
d.judge(99)
}
实例五:定义一个小小计算机的结构体(Calcuator),实现加减乘除四个功能
type Calcuator struct {
num1 float64
num2 float64
}
func (cal *Calcuator)result(operator byte) float64 {
var res float64
switch operator {
case '+':
res = cal.num1 + cal.num2
case '-':
res = cal.num1 - cal.num2
case '*':
res = cal.num1 * cal.num2
case '/':
res = cal.num1 / cal.num2
default:
fmt.Println("输入错误!!")
}
return res
}
func main() {
var e Calcuator
e.num1 = 3.6
e.num2 = 1.2
fmt.Println(e.result('/'))
}
方法和函数的区别
- 调用方式不一样
- 对普通函数,接收者为值类型时,不能将指针类型的数据直接传递,反之亦然
- 对于方法(如struct方法),接收者为值类型时,可以直接用指针类型的变量调用方法,反过来同样也可以
- 不管调用形式如何,真正决定是值拷贝还是地址拷贝,看这个方法是和哪个类型绑定
- 如果是和值类型,比如(p Person),则是值拷贝,如果和指针类型,比如是(p *Person)则是地址拷贝