Go学习笔记-结构体中的方法

方法是什么

  • Go方法是作用在接受者(个人理解成作用对象)上的一个函数,接受者是某种类型的变量,因此方法是一种特殊类型的函数。
  • 接收者可以是任何类型,不仅仅是结构体,Go中的基本类型(int,string,bool等)也是可以,或者说数组的别名类型,甚至可以是函数类型。但是,接受者不能是一个接口类型,因为接口是一个抽象的定义,方法是一个具体实现。
  • 一个类型加上它的方法等价于面向对象中的一个类。一个重要的区别是:在 Go 中,类型的代码和绑定在它上面的方法的代码可以不放置在一起,它们可以存在在不同的源文件,唯一的要求是:它们必须是同一个包的。
  • 类型 T(或 *T)上的所有方法的集合叫做类型 T(或 *T)的方法集。
  • 因为方法是函数,所以同样的,不允许方法重载,即对于一个类型只能有一个给定名称的方法。但是如果基于接收者类型,是有重载的:具有同样名字的方法可以在 2 个或多个不同的接收者类型上存在,比如在同一个包里这么做是允许的
  • 别名类型不能有它原始类型上已经定义过的方法(因为别名类型和原始类型底层是一样的)。

定义方法的格式

 1 func(recv recevier_type)methodName(parameter_list)(return_value_list){} 

  方法名之前,func关键字之后的括号中指定接受者(receiver)。

  如果recv是接受者(receiver)的实例,Method1是recv的方法名,那么方法的调用遵循传统的object.name选择器符号:recv.Method1()。假如recv是一个指针,Go会自动解引用。

 1 package main
 2 
 3 import "fmt"
 4 
 5 type TwoInts struct {
 6     a int
 7     b int
 8 }
 9 func(ti *TwoInts)Add()int{
10     return ti.a + ti.b
11 }
12 
13 func(ti *TwoInts)Plus()(re int){
14     re = ti.a * ti.b
15     return
16 }
17 
18 func(ti *TwoInts)AddOther(param int)(re int){
19     re = ti.a + ti.b +param
20     return
21 }
22 // 结构体上的例子
23 func main(){
24     tt := new(TwoInts)
25     tt.a = 10
26     tt.b = 20
27 
28     fmt.Println(tt.Add())
29     fmt.Println(tt.Plus())
30 
31     ttt := TwoInts{3,5}
32     fmt.Println(ttt.AddOther(7))
33 }
package main

import "fmt"

type IntVetor []int

func (iv IntVetor) Sum(param int) (re int) {
    su := 0
    for _, v := range iv {
        su = su + v
    }
    re = su + param
    return
}
// 非结构体上的例子
func main() {
    tv := IntVetor{3,4,5}
    fmt.Println(tv.Sum(333))
}

  如果想给基本类型添加方法,一般是行不通的,因为基本类型和你添加方法的包不是同一个,会出现编译错误。

 方法和函数的区别

  • 方法只能被其接受者调用
  • 接收者是指针时,方法可以改变接受者的值(或状态),函数也能做到
  • 接受者和方法必须在同一个包内

方法的接受者是值或者指针的区别

  • 当接受者是一个值的时候,这个值是该类型实例的拷贝
  • 如果想要方法改变接受者的数据,就在接受者的指针类型上定义该方法。否则,就在普通的值类型上定义方法。

 总结:指针方法和值方法都可以在指针或者非指针上被调用。也就是说,方法接收者是指针类型时,指针类型的值也是调用这个方法,反之亦然。

内嵌类型的方法和继承

  当一个匿名类型被内嵌在结构体中时,匿名类型的可见方法也同样被内嵌,这在效果上等同于外层类型继承了这些方法,将父类型放在子类型中实现(子类型中的方法,可以直接使用父类型加点子类型方法的方式调用[father.childMethod()])

  但是当父类型和子类类型有相同名字的方法怎么办呢?父类型的方法会覆盖子类型的。

 1 package main
 2 
 3 import "fmt"
 4 
 5 type Child struct {
 6     a, b int
 7     Father// 【重点】这里必须是匿名类型才可以实现继承的效果,否则不可以!!!!!!
 8 }
 9 type Father struct {
10     name string
11 }
12 
13 func (fa *Father) GetName() (re string) {
14     re = chi.name
15     return
16 }
17 
18 func main() {
19     c := Child{1, 3, Father{"Kobe"}}
20     fmt.Println(c.GetName())
21 }

 

posted @ 2018-03-29 15:35  faddei  阅读(294)  评论(0编辑  收藏  举报