12-方法

方法

什么是方法

方法其实就是一个函数,在 func 这个关键字和方法名中间加入了一个特殊的接收器类型接收器可以是结构体类型或者是非结构体类型。接收器是可以在方法的内部访问的。(我们也可以这么理解,结构体是一系列属性的集合,方法和结构体写一块类似于python中的类。)

语法

func (t Type) methodName(parameter list) {
}

Type是结构体(接收器),methodName是方法名。

方法示例   (下面两个示例,一个是对方法没有传参的,一个是传参之后修改nam值的)

package main
import "fmt"
//结构体
type Person struct {
    name string
    age int
    sex int
}
//创建一个方法:给Person结构体一个打印名字的方法
func (a Person)printName()  {
    fmt.Println(a.name)       //bb
}
//创建一个方法:传入一个参数name,修改name值
func (a Person)changeName(name string)  {
    a.name=name
    fmt.Println(a)         //{jj 0 0}
}

func main() {
    p:=Person{name:"bb"}  //给结构体赋值
    p.printName()  //调用方法printName获取name值
    p1:=Person{name:"xxx"}
    p1.changeName("jj")  //传参,调用方法changeName修改name值
    fmt.Println(p1)       //{xxx 0 0}
}

方法中结构体是指针的情况:

package main
import "fmt"
//结构体
type Person struct {
    name string
    age int
    sex int
}

//创建一个方法:结构体是指针情况下,修改name值
func (a *Person)changeName1(name string)  {
    a.name=name
    fmt.Println(*a)
}

func main() {
    var p2 =&Person{name:"zzz"}   //试验不加&也行
    p2.changeName1("kkk")
}
#结果
{kkk 0 0}

为什么已经有函数了还需要方法呢?

package main
import (
    "fmt"
)

type Employee struct {
    name     string
    salary   int
    currency string
}

/*
displaySalary()方法被转化为一个函数,把 Employee 当做参数传入。
*/
func displaySalary(e Employee) {
    fmt.Printf("Salary of %s is %s%d", e.name, e.currency, e.salary)
}

func main() {
    emp1 := Employee{
        name:     "Sam Adolf",
        salary:   5000,
        currency: "$",
    }
    displaySalary(emp1)
}

在上面的程序中,displaySalary 方法被转化为一个函数,Employee 结构体被当做参数传递给它。这个程序也产生完全相同的输出:Salary of Sam Adolf is $5000

既然我们可以使用函数写出相同的程序,那么为什么我们需要方法?这有着几个原因,让我们一个个的看看。

  • Go 不是纯粹的面向对象编程语言,而且Go不支持类。因此,基于类型的方法是一种实现和类相似行为的途径。
  • 相同的名字的方法可以定义在不同的类型上,而相同名字的函数是不被允许的(******)。假设我们有一个 Square 和 Circle 结构体。可以在 Square 和 Circle 上分别定义一个 Area 方法。见下面的程序。
package main
import (
    "fmt"
    "math"
)

type Rectangle struct {
    length int
    width  int
}

type Circle struct {
    radius float64
}

func (r Rectangle) Area() int {
    return r.length * r.width
}

func (c Circle) Area() float64 {
    return math.Pi * c.radius * c.radius
}

func main() {
    r := Rectangle{
        length: 10,
        width:  5,
    }
    fmt.Printf("Area of rectangle %d\n", r.Area())
    c := Circle{
        radius: 12,
    }
    fmt.Printf("Area of circle %f", c.Area())
}

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

package main

import "fmt"
//结构体
type Person struct {
    name string
    age int
    sex int
}

//创建一个方法:值接收器
func (a Person)changeName(name string)  {
    a.name=name
}

//创建一个方法:指针接收器
func (a *Person)changeAge(age int)  {
    a.age=age
}

func main() {
    p:=Person{name:"xxx",age:20}
    fmt.Println(p.name)       //xxx
    p.changeName("jj") 
    fmt.Println(p.name)       //xxx

    fmt.Println(p.age)       //20
    p.changeAge(10)
    fmt.Println(p.age)      //10
}

指针接收器与值接收器

func (值接收器)changeName(name string):在内部修改值,不会影响外部的值
func (指针接收器)changeAge(age int):在内部修改值,会影响外部的值

那什么时候使用指针接收器,什么什么时候使用值接收器当你想修改原值的时候就用指针接收器

匿名字段的方法

package main
import (
    "fmt"
)

type address struct {
    city  string
    state string
}

func (a address) fullAddress() {
    fmt.Printf("Full address: %s, %s", a.city, a.state)
}

type person struct {
    firstName string
    lastName  string
    address
}

func main() {
    p := person{
        firstName: "Elon",
        lastName:  "Musk",
        address: address {
            city:  "Los Angeles",
            state: "California",
        },
    }

    p.fullAddress() //访问 address 结构体的 fullAddress 方法
}

在上面程序的第 32 行,我们通过使用 p.fullAddress() 来访问 address 结构体的 fullAddress() 方法。明确的调用 p.address.fullAddress() 是没有必要的。该程序输出:

Full address: Los Angeles, California

在方法中使用值接收器和在函数中使用值参数

在方法中使用指针接收器和在函数中使用指针参数

package main
import "fmt"

type Person2 struct {
    name string
    age int
    sex int
}
//方法中使用值接收器
func (a Person2)printName()  {
    fmt.Println(a.name)

}
//方法中使用指针接收器
func (a *Person2)printName2()  {
    fmt.Println(a.name)
}
//函数中使用值参数
func printName(a Person2)  {
    fmt.Println(a.name)
}
//在函数中使用指针参数
func printName2(a *Person2)  {
    fmt.Println(a.name)
}

func main() {
    p:=&Person2{name:"lqz"}
    //调用值接收器
    p.printName()
    //调用指针接收器
    p.printName2()
    //调用值函数
    printName(p)
    //调用指针函数
    printName2(&p)
    //不管是指针接收器还是值接收器,都可以使用值来调用
    //不管是指针接收器还是值接收器,都可以使用指针来调用
    //函数中,是什么参数,就得传什么参数

}

在非结构体上的方法

package main
import "fmt"

//重命名
type MyInt int


func (i *MyInt)add()  {
    (*i)++
    fmt.Println(*i)
}

func main() {
    var a MyInt=10
    a.add()
    fmt.Println(a)
}

 

posted @ 2019-12-12 21:06  只会玩辅助  阅读(185)  评论(0编辑  收藏  举报