Go OOP
不同于 Java 从设计上就大量参考了面向对象编程的思想,也不同于 C++ 在 C 的基础上做了 OOP 的调整,Golang 没有直接的类以映射对象,而是采用结构体的方式间接地、简洁地实现 OOP。
类的初始化
对于方法的可见性由方法名开头的大小写决定.如方法名开头为大写则此方法为 public;小写则为 private,仅供内部包调用
// 类的初始化type Person struct { name, id string age int gender string father, mother *Person}
// 绑定方法(不会修改原对象)func (p Person) SayHi() { fmt.Printfln("Hi, I'm ", p.name)}
// 绑定方法(会修改原对象)func (p *Person) SetName(name string) { p.name = name}
// 实例化和调用其方法somebody1 := Person{}somebody2 := Person{name: "somebody2"}somebody1.SayHi()somebody2.SetName("new name")
封装继承多态
- 继承是匿名的:在继承父类时无需为属性命名
- 接口是隐式的:接口声明时的类,在实现时不需要显式指定
- 多态是基于接口实现的
- 空接口
type empty_interface interface{}
可以承载任意类型
// 继承type Student struct { Person // 匿名继承 Person grade int school string}
// 接口创建type Person interface { teach(Student) bool learn() bool}// 接口实现func (s Student) learn() bool { fmt.Printfln("Student %s learn", s.name) return true}func (t Teacher) teach(s Student) bool { fmt.Printfln("Teacher %s teach %s", t.name, s.name) return true}
还有一个父类子类的隐性转换带来的权限问题,此事在 Java 的学习中亦有记载
在下一个例子中,当我们调用 phone.send_wechat()
时会报错,原因是 phone
实例的类型时父类,而父类 Phone
只有一个方法 call()
,只有子类 iPhone
才有 send_wechat()
方法。举个例子,Person
是父类,Athlete
是子类,运动员能百米十秒内,难道所有人类都能做到吗?
type Phone interface { call()}
type iPhone struct { name string}
func (phone iPhone)call() { fmt.Println("Hello, iPhone.")}
func (phone iPhone)send_wechat() { fmt.Println("Hello, Wechat.")}
func main() { var phone Phone phone = iPhone{name:"ming's iphone"} phone.call() phone.send_wechat()}
于是我们只需要修改 phone 实例的类型为 iPhone 即可 phone := iPhone{name:"ming's iphone"}
反射 Reflection
Java 中的反射一般用于通过类的名字,以字符串的方式来获取类对象。而 Golang 中的反射则让我们拥有了获取一个对象的类型、属性及方法的能力
// 创建对象type T intvar x T// 获取对象类型xType := reflect.TypeOf(x)// 获取对象值xValue := reflect.ValueOf(x)v.Type() // 得到直接类型 Tv.Kind() // 得到底层类型 int
type Person struct { Name string Age int}
func (p *Person) setAge(age int) { p.Age = age}
func main() { zari := Person{Name: "zari", Age: 21} zariType := reflect.TypeOf(zari) zariType.Name() // Person zariType.Kind() // struct zariValue := reflect.ValueOf(zari) zariValue.Type() // Person zariValue.Kind() // struct // 获取对象属性和方法(Person类含两个属性,因此循环次数为2) for i := 0; i < zariValue.NumField(); i++ { field := zariValue.Field(i) // 获取属性 fieldName := zariType.Field(i).Name // 获取属性名(Name, Age) fieldType := zariType.Field(i).Type // 获取属性类型(string, int) fieldValue := field.Interface() // 获取属性值(zari, 21) }}