方法
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;
}
}
正文完