Go学习——8.方法

方法

  • 在func关键字和方法名之间存在接收者类型的那些函数,我们称之为方法。
      ------------------接收者
      |   --------------接收者类型
      |   |
func (t Type) methodName(parameter list) {

}
|
|
--------------相当于给接受者t添加了函数methodName,类似于js中的面向对象,给类添加方法,只不过go没有面向对象,所以这么搞
|
|
--------------这样的话,调用methodName就需要t.methodName()来调用了

1.定义和使用一个方法

package main

import (
	"fmt"
)

type Employee struct {
	name string
	age int
}

// 定义一个方法
func (e Employee) displayPersonInfo() {
	fmt.Println("员工", e.name, "的年龄是", e.age, "岁")
}

func main()  {
	emp := Employee {
		name: "Sam",
		age: 18, // 这里最后需要逗号,否则会报错
	}
  
  // 使用方法
	emp.displayPersonInfo()
}

2.指针接收者 VS 值接收者

  • 区别:对带有指针接收者的方法做出的修改对调用者来说是可见的。而值接收者却并非这样。
    • 意思就是,指针接受者的属性值改了,外面也改了,而值接受者,里面改了外面不改,类似于指针是引用,值不是
type Employee struct {
	name string
	age int
}

func (e Employee) displayPersonName(newName string) {
	e.name = newName
}

func (e *Employee) displayPersonAge(newAge int) {
	e.age = newAge
}

func main()  {
	
	emp := Employee {
		name: "Sam",
		age: 18,
	}
	
	fmt.Println(emp.name) // Sam
	emp.displayPersonName("newSam")
	fmt.Println(emp.name) // Sam

	fmt.Println(emp.age) // 18
	(&emp).displayPersonAge(20)
	fmt.Println(emp.age) // 20

	(emp).displayPersonAge(21)
	fmt.Println(emp.age) // 21
	
}
  • 可见,值接收者,方法内部变了,外部不变。
  • 可见,指针接收者,方法内部变了,外部跟着变。
  • 可见,指针接收者在调用方法的时候,&emp 与 emp 一模一样。

3.什么时候使用指针接收,什么时候使用值接收

  • 对于调用者来说,接收者修改了,调用者可见,那么就用指针接收。
    • 通俗地讲:方法里面改了,外面也改,用指针接收
  • 对于复制结构体数据来说,也可以使用指针接收者
    • 比如:某个结构体有很多字段,如果使用这个结构体作为值接收者的话,就需要复制结构体所有的字段,而这样的复制是很昂贵的。如果使用指针接收者,就不需要复制结构体,复制一个指针即可。

4.匿名结构体字段的方法

  • 对于匿名结构体字段,需要调用方法的话,直接调用就可以了
  • 举例:
package main

import (
	"fmt"
)

type Address struct {
	city string
}

type Employee struct {
	name string
	age int
	Address
}

func (a Address) displayAddress() {
	fmt.Println(a.city)
}

func main()  {
	
	emp := Employee {
		name: "Sam",
		age: 18,
		Address: Address { // 这里必须要写成Address: Address {}
			city: "New York",
		}, // 这里要加逗号
	}

	// 调用displayAddress,可以用如下两种方式调用:
	emp.displayAddress() // New York
	emp.Address.displayAddress() // New York
}

5.方法的值接收者 VS 函数的值参数

  • 方法的值接收者既是接收指针,也可以是值接收者
  • 函数的值接收者只能是值接收者
type rectangle struct {
    length int
    width  int
}

func area(r rectangle) {
    fmt.Printf("Area Function result: %d\n", (r.length * r.width))
}

func (r rectangle) area() {
    fmt.Printf("Area Method result: %d\n", (r.length * r.width))
}

func main() {
    r := rectangle{
        length: 10,
        width:  5,
    }
    area(r)
    r.area()

    p := &r // 这是指针,方法可以接收,函数不行

    p.area()//calling value receiver with a pointer
}

6.方法的指针接收者 VS 函数的指针接收者

  • 和值参数类似,指针参数的函数只能接收指针。然而 指针接收者的方法却可以同时接收指针和值接收者。
type rectangle struct {
    length int
    width  int
}

func perimeter(r *rectangle) {
    fmt.Println("perimeter function output:", 2*(r.length+r.width))

}

func (r *rectangle) perimeter() {
    fmt.Println("perimeter method output:", 2*(r.length+r.width))
}

func main() {
    r := rectangle{
        length: 10,
        width:  5,
    }
    p := &r //pointer to r
    perimeter(p) // 函数参数只能是指针


    p.perimeter() // 方法接收者可以是指针

    r.perimeter() // 方法接收者也可以是值

}

7.非结构体接收者的函数

  • 不仅结构体可以作为接收者,非结构体也可以作为接收者。但是非结构体作为接收者有一个很大的限制:
    • 接收者的定义和非接收者的定义必须在同一个包下
  • 举例:
    • 反例:以下例子会报错,在内置数据类型int上添加一个add方法是不允许的,原因是int和方法add不在同一个包下。
    package main
    
    func (a int) add(b int) {
    }
    
    func main() {
    
    }
    
    • 正例:为了解决上述问题,可以为内置类型int创建一个类型别名,然后用这个类型别名来作为接收者去创建一个方法
    package main
    
    var newInt int
    
    func (a newInt) add(b int) {
    }
    
    func main() {
    
    }
    
    
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值