Go 中虽没有class,但依旧有method


通过显示说明receiver来实现与某个类型的组合


只能为同一个包中的类型定义方法


Receiver 可以是类型的值或者指针


不存在方法重载


可以使用值或指针来调用方法,编译器会自动完成转换


从某种意义上来说,方法是函数的语法糖,因为receiver其实就是


方法所接收的第1个参数(Method Value vs. Method Expression)


如果外部结构和嵌入结构存在同名方法,则优先调用外部结构的方法


类型别名不会拥有底层类型所附带的方法


方法可以调用结构中的非公开字段



package main

import (
     "fmt"
)

type A struct {
     Name string
}

type B struct {
     Name string
}

func main() {
     a := A{}  //声明一个结构A,类似于PHP的$a = new A();操作
     a.Print() //然后调用一个A结构的方法
}

//为A结构写方法
//编译器通过receiver接收者来判断是哪个结构类型的方法
//该方法与A结构联系到一起,及附属在A结构上
func (a A) Print() { //(a A就是func的第一个参数,即receiver,a为struct对象的接收者,可以值传递和引用传递,变量结构类型为A,方法名称为Print,Print里的参数和返回类型可有可无。func (a A) Print()和func (a *A) Print(),两者不能同时存在,因为函数名相同
     fmt.Println("我是A结构体的Print方法输出的。")
}



输出:



我是A结构体的Print方法输出的。





package main

import (
     "fmt"
)

type A struct {
     Name string
}

type B struct {
     Name string
}

func main() {
     a := A{}
     a.Print()//虽然这里是指针传递,但是调用的使用a前面不要加&, ,因为Go知道receiver是指针,他自动帮你转了
//类似的如果一个method的receiver是T,你可以在一个*T类型的变量P上面调用这个method,而不需要 *P去调用这个method。所以,你不用担心你是调用的指针的method还是不是指针的method,Go知道你要做的一切,这对于有多年C/C++编程经验的同学来说,真是解决了一个很大的痛苦。
     fmt.Println()

     b := B{}
     b.Print()
     fmt.Println()
}

//很显然,指针传递的可以使原来的值发生改变,而值传递的就不会了
//说明receiver还是遵循参数规则
func (a *A) Print() {
      = "AA"
     fmt.Println("我是A结构体的Print方法输出的。")
}

func (b B) Print() {
      = "BB"
     fmt.Println("我是B结构体的Print方法输出的。")
}



输出:



  我是A结构体的Print方法输出的。



  AA



  我是B结构体的Print方法输出的。





值传递和指针传递



package main

import (
     "fmt"
)

//类型别名
//类似于给int定义一个别名,但是此时的TZ与struct定义的类型使用方法一样,把它当作一个类,可以为其添加方法
type TZ int//注意这不是一个结构体,用了底层类型int整型

func main() {
     //接收者为typeName,而不是*typeName时,调用方法varName.funcName(param)与typeName.funcName(varName, param)一样,如果是*typeName 则不能后者访问
     //接收者为 *typeName时,通过varName.funcName()访问时,等于(&varName).funcName(),即可以不用在varName前面加上"&"取地址
     var a TZ
     a.Print("我是非指针打印!")//官方称为:Method Value
     TZ.Print(a, "我是非指针打印!")//官方称为:Method Expression

     a.pointerPrint("我是指针打印!")//官方称为:Method Value 
}

func (a TZ) Print(s string) {
     fmt.Println(s)
}

func (a *TZ) pointerPrint(s string) {
     fmt.Println(s)
}



输出:



  我是非指针打印!
  我是非指针打印!
  我是指针打印!



访问权限


package main

import (
     "fmt"
)

//访问权限
type A struct {
     name string //注意这时的name首字母为小写,即私有属性
}

//注意:我们所说的首字母大小写的公私有权限问题,是以package为界限的,针对包外的,即除了该main包意外的包,而在包里不管大小写都是可以访问的
func main() {
     a := A{}
     a.Print()
     fmt.Print() //成功输出,说明main函数也能访问结构体私有属性
}

func (a *A) Print() {
      = "GO"
     fmt.Println() //成功输出,说明方法可以访问结构体的私有属性
}




  GO
  GO