Golang支持面向对象编程,支持基本的继承,封装,接口等基本概念,也很容易实现,但是Golang是一种松散的面向对象,约束远没有java,c++那么严格,Golang 可以用结构体来模拟类,并给结构体添加特定方法来实现面向对象的类,来看这样一个例子
我们实现这样一个Animal类(结构体),他有一些基本属性和函数(function)
package main
import "fmt"
type Animal struct { // 动物类的定义
name string
food string
age int
}
func (an *Animal) eat() {
fmt.Printf("I eat "+an.food+"\n") // 注意,此处带来一个对象的属性
}
func (an *Animal) run() {
fmt.Println("Every animal could run") // 此处没有带对象的任何属性
}
func main() {
var abstructAnimal *Animal // 空指针, 表达抽象的动物
var tiger *Animal = &Animal{name:"tiger",food:"meat"}
abstructAnimal.run()
tiger.run()
//abstructAnimal.eat() //compile success,but running throw an panic runtime error: invalid memory address or nil pointer dereference
tiger.eat()
/******* running result ****************
Every animal could run
Every animal could run
I eat meat
*/
}
我们定义了一个类Animal和他的基本属性,方法,并且在主函数中定义了一个空的Animal指针和一个指向一个初始化了的对象tiger,我们分别调用这两个对象的两个方法,发现只有方法不能运行,这是不是很奇怪,按照java的逻辑,taiger已经初始化类,它能运行所有的方法,这很好理解。我们重的说一下空指针abstractAnimal的行为。
可以看到,Animal定义的run方法并不包含不会引用任何的对象字段,这是它能通过的关键
其实,Golang编译器在编译上面的函数eat和run方法的时候,会把他们编译成下面的函数
func eat(an *Animal) {
fmt.Printf("I eat "+an.food+"\n") // 注意,此处带来一个对象的属性
}
func run(an *Animal) {
fmt.Println("Every animal could run") // 此处没有带对象的任何属性
}
看到了吗,这两个方法在编译完后的二进制文件中,其实是该包下的一个普通函数,并不隶属于任何的结构体(类)
但是,你在编写程序的时候,必须要在用tiger.eat() 这样的方式去调用;否则,你通不过go test 命令
更不可能编译成可执行文件。这就是golang的高明之处,在go test(语法检查)阶段强迫程序员不得乱用对象的方法,保证某个方法和对象的绑定,而又在编译后放开了这一限制,这样,你感觉程序员感觉他是在写面向对象程序,最大程度的减少了类似java的NullPointerException。它要求你遵从面向对象的编程范式,但又减少了很多不必要的程序错误。
golang是没有类似java中static关键字的,但是上面的例子已经自适应了java中的静态和非静态方法
上面的run就类似于java中的static方法,语法上隶属于类,java中static不得使用this关键字,这里只需要你不使用animal对象的属性,表达了相同的意思,
而eat方法,就类似于java中的非static方法,它于具体的对象意一一对应,在这里对应这我们在eat函数中使用animal的字段,所以,你必须要实例化后才能调用
术于function和method的区别
function表达的是一个完成特定功能的函数,通常在函数是编程和过程化编程中用到这个术语。
method通常指的是面向对象编程中,仅隶属于某个类的,绑定特定对象的方法,它特别强调某个方法应该属于某个类,一一对应,隶属关系明显
golang在go test阶段表现的是method,而在编译后表现的更多是function的特点
完