Go 的面向对象,语法清奇,思路独特,和传统的面向对象语言如 Java 完全不同,可开阔思路。
谈到面向对象,就不得不提其载体 struct
type 结构体名称 struct{ field1 type field2 type }以上便是其定义的语法,使用也很简单
type Student struct { Name,Address string Age int Score float64 }定义了个 Student 的结构体,里面有几个常用的字段。以下为引用的一种方法
alice := Student{"molaifeng", "北京", 32, 99.5}在 Go 中,方法是指定在数据类型上的,因此如果给上面的 student 结构体指定特有的方法,只需如此做
func (this Student) Speak(str string) { fmt.Println(str); }使用刚刚定义的方法
func main() { alice.Speak("My name is Alice") }其实这个特性和上述介绍的方法一致,因为方法对外提供接口并隐藏实现细节。
继承可以解决代码复用,当多个结构体存在相同的属性(字段)和方法时,可以从这些结构体中抽象出结构体(比如刚才的Student),在该结构体中定义这些相同的属性和方法。
type Pupil struct { Student } type Graduate struct { Student }当然了,结构体也可以实现多重继承,这里就不展开介绍了。
介绍多态之前,还得宕开一笔说下接口,因为这个是实现多态的基础。
interface 类型可以定义一组方法,但是这些不需要实现。并且 interface 不能包含任何变量。到某个自定义类型(比如结构体 Student)要使用的时候,在根据具体情况把这些方法写出来。
type 接口名 interface { method1(参数列表) 返回值列表 method2(参数列表) 返回值列表 } func (t 自定义类型) method1(参数列表) (返回值列表) { //方法实现 } func (t 自定义类型) method2(参数列表) (返回值列表) { //方法实现 }需要说明的是,Go 中的接口,不需要显式的实现。只要一个变量,含有接口类型中的所有方法,那么这个变量就实现这个接口。因此,Go 中没有 implements 这样的关键字。
type Repeat interface { Say() } func (s *Student) Say() { fmt.Println(s.Name) } func main() { var re Repeat = alice re.Say() }还有另一个重要的特点,空接口 interface{} 没有任何方法,所以所有类型都实现了空接口。
type T interface { } func main() { // Stutent 默认实现了空接口 var t T = alice fmt.Println(t) var t1 interface{} = alice num := 8.8 fmt.Println(t1) t1 = num fmt.Println(t1) }接口比继承更加灵活,继承是满足 is a 的关系,而接口只需满足 like a 的关系。
变量(实例)具有多种形态。这里给出个判断变量类型的实例,来了解多态。
package main import "fmt" type Student struct { Name string Score float64 } func JudgeType(items ...interface{}) { for index, x := range items { switch x.(type) { case bool : fmt.Printf("第 %v 个参数是 bool 类型,值是 %v \n", index, x) case float32 : fmt.Printf("第 %v 个参数是 float32 类型,值是 %v \n", index, x) case float64 : fmt.Printf("第 %v 个参数是 float64 类型,值是 %v \n", index, x) case byte: fmt.Printf("第 %v 个参数是 byte 类型,值是 %v \n", index, x) case int, int32, int64: fmt.Printf("第 %v 个参数是 整数类型,值是 %v \n", index, x) case string: fmt.Printf("第 %v 个参数是 string 类型,值是 %v \n", index, x) case Student: fmt.Printf("第 %v 个参数是 Student 类型,值是 %v \n", index, x) case *Student: fmt.Printf("第 %v 个参数是 *Student 类型,值是 %v \n", index, x) default : fmt.Printf("第 %v 个参数是 类型 不确定,值是 %v \n", index, x) } } } func main() { var n1 float32 = 1.1 var n2 float64 = 1.1 var n3 int32 = 1 address := "北京" var b byte = 'a' s1 := Student{} s2 := &Student{} JudgeType(n1, n2, n3, address, b, s1, s2) }之所以接口可以实现类型断言,是因为在上面接口介绍中,说了一个注意点,那就是空接口 interface{} 没有任何方法,所以所有类型都实现了空接口。
最后再给个实例
package main import "fmt" type Usb interface { Start() Stop() } type Phone struct { Name string } func (p Phone) Start() { fmt.Println(p.Name, "手机开始工作") } func (p Phone) Stop() { fmt.Println(p.Name, "手机停止工作") } func (p Phone) Call() { fmt.Println(p.Name, "手机开始打电话") } type Camera struct { Name string } func (c Camera) Start() { fmt.Println(c.Name, "相机开始工作") } func (c Camera) Stop() { fmt.Println(c.Name, "相机停止工作") } type Computer struct { Name string } // 编写一个方法 working 方法,接收一个 usb 接口类型变量 // 只要是实现了 Usb 接口 (所谓实现 Usb 接口,就是指实现了 Usb 接口声明所有方法) func (c Computer) Working(usb Usb) { usb.Start() if p, ok := usb.(Phone); ok { // 关键点在这 p.Call() } usb.Stop() } func main() { var computer Computer var usb [3]Usb usb[0] = Phone{"苹果"} usb[1] = Phone{"联想"} usb[2] = Camera{"尼康"} for _, v := range usb{ computer.Working(v) } }