设为首页 加入收藏

TOP

Go基础系列:Go中的方法(一)
2018-11-01 18:12:17 】 浏览:49
Tags:基础 系列 方法

Go方法简介

Go中的struct结构类似于面向对象中的类。面向对象中,除了成员变量还有方法。

Go中也有方法,它是一种特殊的函数,定义于struct之上(与struct关联、绑定),被称为struct的receiver。

它的定义方式大致如下:

type mytype struct{}

func (recv mytype) my_method(para) return_type {}
func (recv *mytype) my_method(para) return_type {}

这表示my_method()函数是绑定在mytype这个struct type上的,是与之关联的,是独属于mytype的。所以,此函数称为"方法"。所以,方法和字段一样,也是struct类型的一种属性。

其中方法名前面的(recv mytype)(recv *mytype)是方法的receiver,具有了receiver的函数才能称之为方法,它将函数和type进行了关联,使得函数绑定到type上。至于receiver的类型是mytype还是*mytype,后面详细解释。

定义了属于mytype的方法之后,就可以直接通过mytype来调用这个方法:

mytype.my_method()

来个实际的例子,定义一个名为changfangxing的struct类型,属性为长和宽,定义属于changfangxing的求面积的方法area()。

package main

import "fmt"

type changfangxing struct {
    length float64
    width  float64
}

func (c *changfangxing) area() float64 {
    return c.length * c.width
}

func main() {
    c := &changfangxing{
        2.5,
        4.0,
    }
    fmt.Printf("%f\n",c.area())
}

方法的一些注意事项

1.方法的receiver type并非一定要是struct类型,type定义的类型别名、slice、map、channel、func类型等都可以。但内置简单数据类型(int、float等)不行,interface类型不行

package main

import "fmt"

type myint int

func (i *myint) numadd(n int) int {
    return n + 1
}

func main() {
    n := new(myint)
    fmt.Println(n.numadd(4))
}

以slice为类型,定义属于它的方法:

package main

import "fmt"

type myslice []int

func (v myslice) sumOfSlice() int {
    sum := 0
    for _, value := range v {
        sum += value
    }
    return sum
}

func main() {
    s := myslice{11, 22, 33}
    fmt.Println(s.sumOfSlice())
}

2.struct结合它的方法就等价于面向对象中的类。只不过struct可以和它的方法分开,并非一定要属于同一个文件,但必须属于同一个包。所以,没有办法直接在int、float等内置的简单类型上定义方法,真要为它们定义方法,可以像上面示例中一样使用type定义这些类型的别名,然后定义别名的方法

3.方法有两种类型(T Type)(T *Type),它们之间有区别,后文解释。

4.方法就是函数,所以Go中没有方法重载(overload)的说法,也就是说同一个类型中的所有方法名必须都唯一。但不同类型中的方法,可以重名。例如:

func (a *mytype1) add() ret_type {}
func (a *mytype2) add() ret_type {}

5.type定义类型的别名时,别名类型不会拥有原始类型的方法。例如mytype上定义了方法add(),mytype的别名new_type不会有这个方法,除非自己重新定义。

6.如果receiver是一个指针类型,则会自动解除引用。例如,下面的a是指针,它会自动解除引用使得能直接调用属于mytype1实例的方法add()。

func (a *mytype1) add() ret_type {}
a.add()

7.(T Type)(T *Type)的T,其实就是面向对象语言中的this或self,表示调用该实例的方法。如果愿意,自然可以使用self或this,例如(self Type),但这是可以随意的。

8.方法和type是分开的,意味着实例的行为(behavior)和数据存储(field)是分开的,但是它们通过receiver建立起关联关系

方法和函数的区别

其实方法本质上就是函数,但方法是关联了类型的,可以直接通过类型的实例去调用属于该实例的方法。

例如,有一个type person,如果定义它的方法setname()和定义通用的函数setname2(),它们要实现相同的为person赋值名称时,参数不一样:

func (p *person) setname(name string) {
    p.name = name
}

func setname2(p *person,name string) {
    p.name = name
}

通过函数为person的name赋值,必须将person的实例作为函数的参数之一,而通过方法则无需声明这个额外的参数,因为方法是关联到person实例的。

值类型和指针类型的receiver

假如有一个person struct:

type person struct{
    name string
    age int
}

有两种类型的实例:

p1 := new(person)
p2 := person{}

p1是指针类型的person实例,p2是值类型的person实例。虽然p1是指针,但它也是实例。在需要访问或调用person实例属性时候,如果发现它是一个指针类型的变量,Go会自动将其解除引用,所以p1.name在内部实际上是(*p1).name。同理,调用实例的方法时也一样,有需要的时候会自动解除引用。

除了实例有值类型和指针类型的区别,方法也有值类型的方法和指针类型的区别,也就是以下两种receiver:

func (p person) setname(name string) { p.name = name }
func (p *person) setage(age int) { p.age = age }

setname()方法中是值类型的receiver,setage()方法中是指针类型的receiver。它们是有区别的。

首先,setage()方法的p是一个指针类型的person实例,所以方法体中的p.age实际上等价于(*p).age

再者,方法就是函数,Go中所有需要传值的时候,都是按值传递的,也就是拷贝一个副本

setname()中,除了参数name string需要拷贝,receiver部分(p person)也会拷贝,而且它明确了要拷贝的对象是值类型的实例
编程开发网

首页 上一页 1 2 3 下一页 尾页 1/3/3
】【打印繁体】【投稿】【收藏】 【推荐】【举报】【评论】 【关闭】 【返回顶部
上一篇Go基础系列:接口类型探测和type-.. 下一篇for 循环变量作用域的小坑

评论

帐  号: 密码: (新用户注册)
验 证 码:
表  情:
内  容:

array(4) { ["type"]=> int(8) ["message"]=> string(24) "Undefined variable: jobs" ["file"]=> string(32) "/mnt/wp/cppentry/do/bencandy.php" ["line"]=> int(214) }