Golang - 面对"对象"


Golang - 面对"对象"

 

Golang - 面对"对象"

1. 简介

  • go语言对于面向对象的设计非常简洁而优雅
  • 没有封装、继承、多态这些概念,但同样通过别的方式实现这些特性
  • 封装:通过方法实现
  • 继承:通过匿名字段实现
  • 多态:通过接口实现

2. 匿名字段

go支持只提供类型而不写字段名的方式,也就是匿名字段,也称为嵌入字段

//package 声明开头表示代码所属包 package main import "fmt" //定义人的结构体 type Person struct { name string sex string age int } //学生 type Student struct { //匿名字段 //默认Student包含了Person所有字段 Person id int addr string } func main() { s2 := Student{Person:Person{"约汉","female",10},id:2} fmt.Println(s2) } //{{约汉 female 10} 2 }

同名字段的情况

//package 声明开头表示代码所属包 package main import "fmt" //定义人的结构体 type Person struct { name string sex string age int } //学生 type Student struct { //匿名字段 //默认Student包含了Person所有字段 Person id int addr string //同名字段 name string } func main() { var s Student //就近赋值 s.name = "约汉" fmt.Println(s) //若给外面赋值 s.Person.name = "接客" fmt.Println(s) } //{{ 0} 0 约汉} //{{接客 0} 0 约汉}

所有的内置类型和自定义类型都是可以作为匿名字段去使用

package main import "fmt" //定义人的结构体 type Person struct { name string sex string age int } //自定义类型 type mystr string //学生 type Student struct { //匿名字段 //默认Student包含了Person所有字段 Person //内置 int mystr } func main() { //初始化 s1 := Student{Person{"约汉","male",18},1,"bj"} fmt.Println(s1) fmt.Println(s1.name) }

指针类型匿名字段

//package 声明开头表示代码所属包 package main import "fmt" //定义人的结构体 type Person struct { name string sex string age int } //学生 type Student struct { //匿名字段 //默认Student包含了Person所有字段 *Person //内置 id int addr string } func main() { s1 := Student{&Person{"约汉","male",18},1,"bj"} fmt.Println(s1) fmt.Println(s1.name) } //{0xc0420661e0 1 bj} //约汉

3. 方法

4. 包和封装

5. 接口

  • 在面向对象编程中,一个对象其实也就是一个简单的值或者一个变量,在这个对象中会包含一些函数
  • 这种带有接收者的函数,我们称为方法,本质上,一个方法则是一个和特殊类型关联的函数
  • 方法的语法如下
  • func (接收参数名 接收类型) 方法名(参数列表)(返回值)
  • 可以给任意自定义类型(包括内置类型,但不包括指针类型)添加相应的方法
  • 接收类型可以是指针或非指针类型
  • 为类型添加方法(为基础类型添加方法和为结构体类型添加方法)
    • 基础类型

        //package 声明开头表示代码所属包 package main import "fmt" //任务:定义方法实现2个数相加 type MyInt int //传统定义方式,面向过程 func Add(a, b MyInt) MyInt { return a + b } //面向对象 func (a MyInt) Add(b MyInt) MyInt { return a + b } func main() { var a MyInt = 1 var b MyInt = 1 fmt.Println("Add(a,b)=", Add(a, b)) //调用面向对象的方法 fmt.Println("a.Add(b)=",a.Add(b)) } //Add(a,b)= 2 //a.Add(b)= 2
    • 结构体类型

        //package 声明开头表示代码所属包 package main import "fmt" type Person struct { name string sex string age int } //为Person添加方法 func (p Person) PrintInfo() { fmt.Println(p.name, p.sex, p.age) } func main() { p := Person{"接客", "male", 18} p.PrintInfo() }
    • 值语义和引用语义

        //package 声明开头表示代码所属包 package main import "fmt" type Person struct { name string sex string age int } //设置指针作为接收者的方法,引用语义 func (p *Person) SetInfoPointer() { (*p).name = "接客" p.sex = "female" p.age = 22 } //值作为接收者,值语义 func (p Person) SetInfoValue() { p.name = "约汉" p.sex = "male" p.age = 20 } func main() { //指针作为接收者的效果 p1 := Person{"撸死", "male", 19} fmt.Println("函数调用前=", p1) (&p1).SetInfoPointer() fmt.Println("函数调用后=", p1) fmt.Println("================寂寞的分割线=================") //值作为接收者的效果 p2 := Person{"约汉", "male", 18} fmt.Println("函数调用前=", p2) p2.SetInfoValue() fmt.Println("函数调用后=", p2) } //函数调用前= {撸死 male 19} //函数调用后= {接客 female 22} //================寂寞的分割线================= //函数调用前= {约汉 male 18} //函数调用后= {约汉 male 18}
    • 方法的继承

        package main import "fmt" type Person struct { name string sex string age int } //为Person定义方法 func (p *Person) PrintInfo() { fmt.Printf("%s,%s,%d\n",p.name,p.sex,p.age) } type Student struct { Person id int addr string } func main() { p :=Person{"接客","male",18} p.PrintInfo() //学生也去调,方法继承 s := Student{Person{"接客","male",18},2,"bj"} s.PrintInfo() }
    • 方法的重写

        package main import "fmt" type Person struct { name string sex string age int } //为Person定义方法 func (p *Person) PrintInfo() { fmt.Printf("%s,%s,%d\n", p.name, p.sex, p.age) } type Student struct { Person id int addr string } //Student定义方法,实际上就相当于方法重写 func (s *Student) PrintInfo() { fmt.Printf("Student:%s,%s,%d\n", s.name, s.sex, s.age) } func main() { p := Person{"接客", "male", 18} p.PrintInfo() //学生也去调,方法继承 s := Student{Person{"接客", "male", 18}, 2, "bj"} s.PrintInfo() //显式调用 s.Person.PrintInfo() }
    • 方法值和方法表达式

        package main import "fmt" type Person struct { name string sex string age int } func (p *Person) PrintInfoPointer() { //%p是地址,%v是值 fmt.Printf("%p,%v\n", p, p) } func main() { p := Person{"接客", "male", 18} //传统的调用方法的方式 p.PrintInfoPointer() //使用go方法值特性调用 pFunc1 := p.PrintInfoPointer pFunc1() //使用go方法表达式调用 pFunc2 := (*Person).PrintInfoPointer pFunc2(&p) }

练习:创建属性的getter和setter方法并进行调用

    package main import "fmt" type Dog struct { name string //1公 0母 sex int } //封装dog的方法 //setter func (d *Dog) SetName(name string) { d.name = name } //getter func (d *Dog) GetName() string { return d.name } //咬人 func (d *Dog) bite() { fmt.Printf("让本汪%s 来给你上课...", d.name) } func main() { d := Dog{"二哈", 1} d.bite() }

4. 包和封装

  • 方法首字母大写:public
  • 方法首字母小写:private
  • 为结构体定义的方法必须放在同一个包内,可以是不同的文件
  • 上面代码复制到test包中,在test02包中进行调用,需要调用的方法名首字母大写

5. 接口

  • go语言中,接口(interface)是一个自定义类型,描述了一系列方法的集合
  • 接口不能被实例化
  • 接口定义语法如下
  • type 接口名 interface{}
  • PS:接口命名习惯以er结尾
  • 接口定义与实现

      package main import "fmt" //定义人的接口 type Humaner interface { //说话 Say() } //学生结构体 type Student struct { name string score int } //Student实现Say()方法 func (s *Student) Say() { fmt.Printf("Student[%s,%d] 瞌睡不断\n", s.name, s.score) } type Teacher struct { name string group string } //老师实现接口 func (t *Teacher) Say() { fmt.Printf("Teacher[%s,%s] 毁人不倦\n", t.name, t.group) } //自定义类型 type MyStr string //自定义类型实现方法 func (str MyStr) Say() { fmt.Printf("MyStr[%s] 同志醒醒,还有个bug\n", str) } func WhoSay(i Humaner) { i.Say() } func main() { s := &Student{"约汉", 88} t := &Teacher{"撸死", "Go语言"} var tmp MyStr = "接客" s.Say() t.Say() tmp.Say() //go的多态,调用同一个接口,不同表现 WhoSay(s) WhoSay(t) WhoSay(tmp) //make()创建 x := make([]Humaner, 3) x[0], x[1], x[2] = s, t, tmp for _, value := range x { value.Say() } }
    • 接口继承

        package main import "fmt" //定义人的接口 type Humaner interface { //说话 Say() } type Personer interface { //等价于写了Say() Humaner Sing(lyrics string) } //学生结构体 type Student struct { name string score int } //Student实现Say()方法 func (s *Student) Say() { fmt.Printf("Student[%s,%d] 瞌睡不断\n", s.name, s.score) } func (s *Student) Sing(lyrics string) { fmt.Printf("Student sing[%s]!!\n", lyrics) } func main() { s := &Student{"约汉", 88} var p Personer p = s p.Say() p.Sing("互撸娃") }
    • 空接口:空interface{}不包含任何方法,空接客可以存储任意类型的值
    • 类型查询
      • comma-ok断言

          package main import "fmt" //空接口 type Element interface{} type Person struct { name string age int } func main() { //切片 list := make([]Element, 3) //int list[0] = 1 list[1] = "Hello" list[2] = Person{"luhan", 18} //遍历 for index, element := range list { //类型断言:value ,ok = element.(T) //value 是变量的值,ok是返回的布尔值,element是接口变量,T是断言类型 if value, ok := element.(int); ok { fmt.Printf("list[%d]是int类型,值是%d\n", index, value) } else if value, ok := element.(int); ok { fmt.Printf("list[%d]是int类型,值是%d\n", index, value) } else if value, ok := element.(Person); ok { fmt.Printf("list[%d]是Person类型,值是[%s,%d]\n", index, value.name, value.age) } else { fmt.Printf("list[%d]是其他类型\n", index) } } }
      • switch测试

        package main import "fmt" //空接口 type Element interface{} type Person struct { name string age int } func main() { //切片 list := make([]Element, 3) //int list[0] = 1 list[1] = "Hello" list[2] = Person{"luhan", 18} //遍历 for index, element := range list { switch value := element.(type) { case int: fmt.Printf("list[%d]是int类型,值是%d\n", index, value) case string: fmt.Printf("list[%d]是string类型,值是%s\n", index, value) default: fmt.Printf("list[%d]是其他类型\n", index) } } }
 
 


免责声明!

本站转载的文章为个人学习借鉴使用,本站对版权不负任何法律责任。如果侵犯了您的隐私权益,请联系本站邮箱yoyou2525@163.com删除。



 
粤ICP备18138465号  © 2018-2025 CODEPRJ.COM