Go – 方法
方法
1. 方法的声明
在函数声明时,在其名字之前加一个变量,既是一个方法。
Example:
package demo
// 声明一个正方形结构体
//x, y坐标
type Square struct {
x int
y int
}
//声明一个方法计算Square 的面积
func (s Square) Area() int {
return s.x * s.y
}
(下面这段话出自于 《Go语言圣经》)
在上面的代码中,参数s 叫做方法的接受器(receiver),在早期的面相对象语言中将调用一个方法称为“向一个对象发送消息”。
在Go语言中我们可以任意的选择接受器的名字。但是由于经常会被用到,习惯建议用其类型的第一个字母。如Square的s,作为接受器。
2. Receiver的类型
一般分为两种类型。一种是指针类型,一种是非指针类型(如上的代码)。
指针类型,还是以上面Square为例
Example:
package demo
// 声明一个正方形结构体
//x, y坐标
type Square struct {
x int
y int
}
//声明一个方法计算Square 的面积
func (s *Square) Area() int {
return s.x * s.y
}
区别?如何选择?
在解释区别之前,先说下函数的参数。
当调用一个函数时,会对其每一个参数值进行拷贝,如果一个函数需要更新一个变量,或者函数的其中一个参数是在太大,希望能够避免进行这种默认的拷贝,这个时候我们就需要用到指针了。出自于 《Go语言圣经》
Note:其实非指针类型也可以更新变量。因为原始对象和拷贝对象只是一个别名而已,实际上他们指向的对象使一样的。修改非指针类型拷贝后的对象也可以修改变量。
如何选择:
- 不管method的receiver是指针类型还是非指针类型,都是可以通过指针/非指针类型进行调用的,因为编译器会做类型的转换处理
- 声明一个method的receiver该是指针类型还是非指针类型的时候,只需要考虑两个因素:
- 这个对象本身是不是特别大,如果特别大建议声明成指针类型,因为非指针类型会进行一次拷贝
- 如果用指针类型作为receiver,一定要注意,指针类型指向的始终是一块儿内存地址。就算对其进行了拷贝,也是指向同一内存地址。
嵌入结构体类型来扩展类型
先来个Example再解释:
package main
//Animal 动物
type Animal struct {
Name string
Food map[string]interface{}
}
//Dog 狗
type Dog struct {
Animal
PetName string // 爱称 比如:大哥、坦克、子弹等等
}
上面代码就是嵌入结构体类型
如果只看这句话,很难理解到底什么意思。就好像其他编程语言面向对象类的继承。比如PHP、JAVA的子类通过关键字extends继承了父类(注意其实按照类的继承来理解是错误的,并不等价。这里只是为了便于理解)
Java
public class Animal {
static String Name;
static HashMap<String, Object> Food;
}
public class Dog extends Animal{
static String PetName;
public static void main(String[] args) {
System.out.println(PetName);
System.out.println(Name);
System.out.println(Food);
}
}
PHP
class Animal {
protected $name;
protected $food;
}
class Dog extends Animal {
private $petName;
public function test() {
var_dump($this->petName) . PHP_EOL;
var_dump($this->name) . PHP_EOL;
var_dump($this->food) . PHP_EOL;
}
}