go语言方法-学习笔记
方法
什么是方法
方法其实和函数一样,只不过方法指定了接收者。
接收者可以是明明类型或者是结构体类型中的值或者指针。
语法
语法:
func (接收者) 方法名(参数)(返回值){
}
接收者类型可以是(几乎)任何类型,不仅仅是结构体类型:任何类型都可以有方法,甚至可以是函数类型,可以是 int、bool、string 或数组的别名类型。但是接收者不能是一个接口类型,因为接口是一个抽象定义,但是方法却是具体实现;如果这样做会引发一个编译错误:invalid receiver type…。
最后接收者不能是一个指针类型,但是它可以是任何其他允许类型的指针。
因为方法是函数,所以不允许方法重载,即对于一个类型只能有一个给定名称的方法。但是如果基于接收者类型,是有重载的:具有同样名字的方法可以在 2 个或多个不同的接收者类型上存在,比如在同一个包里这么做是允许的:
func (a *denseMatrix) Add(b Matrix) Matrix
func (a *sparseMatrix) Add(b Matrix) Matrix
下面举个小例子:
func main() {
p := People{Name: "zhang san", Age: 99, Address: "China"}
p.sayHello() //hello, zhang san
}
type People struct {
Name string
Age int
Address string
}
func (p People) sayHello() {
fmt.Println("hello, ", p.Name)
}
与函数对比
方法与函数的意义实际上是不一样的,函数只是一段功能性代码,可以直接调用。
而方法是某个类别的行为,需要指定接受者来进行调用。
还有一点不同就是,方法的名字可以相同,但指定接收者必须是不一样的。
变量作用域
go语言的变量可以在三个地方声明:
- 函数内定义,局部变量
- 函数外定义,全局变量
- 函数定义的变量,形式参数
局部变量
在函数体内声明的变量称之为局部变量,他们的作用域仅仅在函数体内,参数与返回值都是局部变量。
全局变量
函数体外都变量称之为全局变量,首字母大写的全局变量可以在整个包甚至外部的包使用。
继承
go语言实际上没有太过明显的面向对象思想,但是我们可以模拟继承。
-
模拟继承:is - a
type A struct{
field
}
type B struct{
A // 匿名字段
}
-
模拟聚合关系:has - a
t ype C struct{
c C
}
子类打印父类方法:
func main() {
p := People{Name: "zhang san", Age: 99, Address: "China"}
s := Student{p, "qinghua"}
s.printInfo() //{zhang san 99 China}
}
type People struct {
Name string
Age int
Address string
}
type Student struct {
People
school string
}
func (p People) printInfo() {
fmt.Println(p)
}
方法的命名
在编程中一些基本操作会一遍又一遍的出现,比如打开(Open)、关闭(Close)、读(Read)、写(Write)、排序(Sort)等等,并且它们都有一个大致的意思:打开(Open)可以作用于一个文件、一个网络连接、一个数据库连接等等。具体的实现可能千差万别,但是基本的概念是一致的。在 Go 语言中,通过使用接口(参考 第 11 章),标准库广泛的应用了这些规则,在标准库中这些通用方法都有一致的名字,比如 Open()
、Read()
、Write()
等。想写规范的 Go 程序,就应该遵守这些约定,给方法合适的名字和签名,就像那些通用方法那样。这样做会使 Go 开发的软件更加具有一致性和可读性。比如:如果需要一个 convert-to-string 方法,应该命名为 String()
,而不是 ToString()
。
多重继承
在如 C++、Java、C# 和 Ruby 这样的面向对象语言中,方法在类的上下文中被定义和继承:在一个对象上调用方法时,运行时会检测类以及它的超类中是否有此方法的定义,如果没有会导致异常发生。
在 Go 语言中,这样的继承层次是完全没必要的:如果方法在此类型定义了,就可以调用它,和其他类型上是否存在这个方法没有关系。在这个意义上,Go 具有更大的灵活性。
请发表评论