面对过程强调过程,面向对象强调对象
包括三个内容
- 匿名字段
- 方法
- 接口
匿名字段
可以理解为用类型别名来进行嵌套等操作,解释不太清楚,属于方便自己的操作
- 可以分为3段内容
- 普通匿名字段
- 指针类型匿名字段
- 多重继承匿名字段
慕课网老师说不支持继承和多态(存疑)
定位就是使用类型别名 type 名字 struct{}
普通匿名字段
type Person struct { //夫类
id int
name string
age int
}
type Student1 struct { // 结构体嵌套 子类
Person //匿名字段 只有类型 没有名字
score int
}
func main51() {
var s1 Student1 = Student1{
Person: Person{
id: 1,
name: "A",
age: 18,
},
score: 98,
}
var s2 Student1 =Student1{Person{2,"B",18},98}
//自动推导
s3:=Student1{Person{3,"C",18},102}
fmt.Println(s1,s2,s3)
//指定初始化成员
s4:=Student1{score: 99}
fmt.Println(s4)
s5:=Student1{Person{name: "小鸡"},80}
fmt.Println(s5)
}
func main() {
var s1 Student1 =Student1{Person{2,"B",18},98}
//成员操作 .操作符
s1.score=87
s1.id=110
s1.Person.age=25
s1.Person=Person{1,"V",12}
fmt.Println(s1)
}
指针类型匿名字段
package main
import "fmt"
type Person2 struct { //夫类
id int
name string
age int
}
type Student2 struct { // 结构体嵌套 子类
*Person2 //匿名字段 只有类型 没有名字
score int
}
func main() {
var s Student2
s.score=90
fmt.Println(s) //打印出 { 90}
//s.*Person2.id=1
s.Person2=new(Person2) //创建出一块新的地址来储存内容
s.name="小A"
s.id=11
s.age=20
fmt.Println(s)//打印出 {0xc0000a63c0 90}
fmt.Println(s.name,s.age,s.id)//打印出 小A 20 11
s.Person2=&Person2{
id: 31,
name: "e",
age: 10,
}
fmt.Println(s.name,s.age,s.id)//打印出 e 10 31
}
多重继承匿名字段
package main
import "fmt"
type person04 struct {//父类
name string
sex string
age int
}
type Person4 struct { //父类
id int
addr string
}
type Student4 struct { // 结构体嵌套 子类
//结构体成员为多个匿名字段
Person4 //匿名字段 只有类型 没有名字
person04
score int
}
type human struct {
Student4 //包含多个匿名字段
country string
}
func main() {
var s1 Student4
s1=Student4{
Person4:Person4{
id: 1,
addr: "北京路",
},
person04:person04{
name: "du",
sex: "男",
age: 21,
},
score: 100,
}
s2:=Student4{Person4{1,"贵州"},person04{"zhao","男",18},21}
var s3 Student4
s3.age=1
s3.name="a"
s3.id=1
s3.score=1
s3.sex="男"
s3.addr="无语"
//3个嵌套 爷父孙嵌套
s4:=human{Student4{Person4{1,"北京路"},person04{"龙","男",19},100},"china"}
fmt.Println(s1)
fmt.Println(s2)
fmt.Println(s3)
fmt.Println(s4)
}
慕课老师补充要点
自定义工厂函数,注意返回局部变量的地址!
package main
import "fmt"
type treenode struct {
value int
left,right *treenode
}
//工程函数
func createNode(value int)*treenode {
return &treenode{value: value}
}
func main() {
//var a treenode
//fmt.Println(a) {0 }
a:=treenode{value: 3}
a.left=&treenode{} //&{0 0xc0000040a8}
a.right=&treenode{5,nil,nil} //&{5 }
a.left.right = new(treenode) //&{0 }
a.right.left = createNode(2) //&{2 }
//nodes:=[]treenode{
// {value: 3},
// {},
// {6,nil,&a},
//}
//fmt.Println(nodes)
}
方法
除了名字和年龄,猫和狗的行为不同,行为可以用方法描述
方法和函数差不多,但方法不是函数
函数名和方法名重名没有影响
方法的定义
func (对象)方法名(函数参数列表)返回值 {
代码体
}
函数的定义
func 函数名(函数参数列表)返回值 {
代码体
}
具体代码
package main
import "fmt"
type cat struct { //除了名字和年龄,猫和狗的行为不同,行为可以用方法描述
name string
age int
}
type dog struct {
name string
age int
}
//方法的定义
//func (对象)方法名(函数参数列表)返回值 {
//代码体
//}
//函数的定义
//func 函数名(函数参数列表)返回值 {
//代码体
//}
func cats() {
fmt.Println("喵喵叫")
}
//方法: 需要绑定对象
// 结构体类型 可以成为对象类型
// 结构体作为接受者
//所有cat都能用
func (c cat)show() {
//fmt.Println("喵喵叫")
fmt.Printf("我是%s,喵喵\n",c.name)
}
func (d dog)show() {
//fmt.Println("汪汪叫")
fmt.Printf("我是%s,汪汪\n",d.name)
}
//函数名和方法名重名没有影响
//方法与方法名重名也没有影响,因为对象不同
func main() {
//对象创建
c:=cat{"旺财",2}
var c1 cat
//c1=cat{"小狗",2}
//fmt.Println(c1)
fmt.Println(c)
//对象.方法 包.函数 结构体.成员
c.show()
c1.show()
//cats() //函数调用
var d dog
d=dog{"旺财二号",2}
fmt.Println(d)
d.show()
}
方法的指针运用
/对象的不同 方法名相同 不冲突
//方法调用中 方法的接受者从普通的对象类型变成指针类型对象
//普通类型和指针类型表示的是相同对象的类型
//值传递(s student7) 地址传递(s *student7)
func (s *student7)Print() {
s.score=-8
fmt.Println(*s)
}
func main(){
stu:=student7{"春哥",8,-5}
stu1:=student7{
name: "春哥2号",
age: 28,
score: 100,
}
//值传递
//如果想要修改实参中的值就要地址传递,使用指针进行地址传递
stu.Print()
fmt.Println(stu)
stu1.Print()
fmt.Println(stu1)
}
输出结果
{春哥 8 -8}
{春哥 8 -8}
{春哥2号 28 -8}
{春哥2号 28 -8}
方法的继承
- 子类可以继承父类 可以继承属性和方法
- 父类不能继承子类 不管是属性还是方法
type person01 struct {//父类
id int
name string
age int
}
type student01 struct {//子类
person01 //匿名字段
class int
}
func (a *person01)PrintInfo() {
//方法建议使用指针类型
a.id=3
fmt.Printf("编号%d\n",a.id)
fmt.Printf("编号%s\n",a.name)
fmt.Printf("编号%d\n",a.age)
}
func main() {
var a person01
a=person01{1,"good boy",18}
a.PrintInfo()
//子类可以继承父类 可以继承属性和方法
//父类不能继承子类 不管是属性还是方法
s:=student01{person01{2,"du",2},100}
s.PrintInfo()
方法值和方法表达式
后期开发中的过程 闭包中用到
type person10 struct {
name string
age int
id int
}
//接受者都是p,方法名不能重名
func (p person10)PrintInfo1() {
fmt.Printf("%p,%v\n",&p,p)
}
//建议使用指针类型
func (p *person10)PrintInfo2() {
fmt.Printf("%p,%v\n",p,*p)
}
func main() {
p:=person10{"xz",19,1}
p.PrintInfo1() //0xc0000463e0,{xz 19 1}
p.PrintInfo2() //0xc0000463c0,{xz 19 1}
fmt.Printf("%T\n",p.PrintInfo1) //类型是func()
//方法值 隐式传递 隐藏的是接受者 绑定实力
//var pfunc1 func()
//对象相同,但是函数类型不同 不能赋值
//函数类型相同 可以赋值
pfunc1:=p.PrintInfo1
pfunc1() //0xc000046460,{xz 19 1}
//pfunc1()等同于p.PrintInfo2()
//方法表达式 显示传参
pfunc2:=person10.PrintInfo1
pfunc2(p)
pfunc3:=(*person10).PrintInfo1
pfunc3(&p)
}
接口
接口是规范或者一种标准
- 定义和使用
type 接口名er interface
1.如何使用接口
接口定义的规则在方法中必须实现
package main
import "fmt"
//先定义接口 一般接口以er结尾 根据接口实现功能
type Humaner interface {
//方法的声明
sayhi()
}
type student11 struct {
name string
age int
score int
}
func (s *student11)sayhi() {
fmt.Printf("大家好我是%s,我今天%d岁,我这次考了%d分\n",s.name,s.age,s.score)
}
type teacher11 struct {
name string
age int
subject string
}
func (s *teacher11)sayhi() {
fmt.Printf("大家好我是%s,我今天%d岁,我这次教%s课",s.name,s.age,s.subject)
}
func main() {
//定义接口变量
var h Humaner
//接口是一种数据类型,可以接受满足对象的信息
//接口是虚的 方法是实的
//方法只负责定义规则 方法实现规则
//接口定义的规则在方法中必须实现
a:=student11{"张三",18,100}
//将对象信息赋值给接口类型变量 满足接口中的方法的声明格式
h=&a
h.sayhi()
t:=teacher11{name:"李华", age:45,subject: "体育"}
fmt.Printf("%T\n",h) //*main.student11
h=&t
h.sayhi()
//a:=student11{"张三",18,100}
//a.sayhi()
//t:=teacher11{
// name: "李华",
// age: 45,
// subject: "体育",
//}
//t.sayhi()
}
接口的多态
感觉非常好用,比之前的方法简单
多态的具体实现方法:就是新建一个函数func 函数名(a任意名字 接口){a任意名字.方法名}
,将接口作为函数参数,传入方法,而后在主方法中用函数将值的地址传进来,大概也许应该是这样的吧
package main
import "fmt"
//先定义接口 一般接口以er结尾 根据接口实现功能
type Humaner interface {
//方法的声明
sayhi()
}
//多态的实现
//将接口作为函数参数 实现多态
func sayhello(h Humaner){
h.sayhi()
}
type student11 struct {
name string
age int
score int
}
func (s *student11)sayhi() {
fmt.Printf("大家好我是%s,我今天%d岁,我这次考了%d分\n",s.name,s.age,s.score)
}
type teacher11 struct {
name string
age int
subject string
}
func (s *teacher11)sayhi() {
fmt.Printf("大家好我是%s,我今天%d岁,我这次教%s课",s.name,s.age,s.subject)
}
func main() {
a:=student11{"张三",18,100}
//调用多态函数
sayhello(&a)
t:=teacher11{name:"李华", age:45,subject: "体育"}
sayhello(&t)
}
计算器例子
package main
import "fmt"
type operater interface {
//方法声明 返回值
result() int
}
type operate struct {//父类
num1 int
num2 int
}
type add struct {//加法子类
operate
}
func (a *add)result() int {
return a.num1+a.num2
}
type del struct {//减法子类
operate
}
func (d *del)result() int {
return d.num1-d.num2
}
//多态的实现
func jishuang(j operater) {
v:=j.result() //要用变量为接受返回值
fmt.Println(v)
}
func main() {
//两种写法
//1.
//var c add
//c.num1=12
//c.num2=13
//g:=c.result()//返回值需要一个变量来接受
//fmt.Println(g)
//2.
//普通的接口使用
var o operater
a:=add{operate{1,2}}
o=&a
b:=o.result()
fmt.Println(b)
//b:=a.result() //返回值需要一个变量来接受
//fmt.Println(b)
d:=del{operate{34,5}}
o=&d
o.result()
//f:=d.result()
//fmt.Println(f)
//多态实现
jishuang(&a)
jishuang(&d)
}
接口的继承与转换
接口的继承:与其他的继承差不多,在一个接口中加入另一个接口并追加新的东西,比如下面代码的sing,而后通过函数的方法去实现
接口的转换:humaner1是子集,person2是超集,超集可以把值赋给子集,而反过来不行
type Humaner1 interface {//子集
//方法的声明
sayhi()
}
type personer2 interface {//超集
Humaner1
sing(string)
}
type student12 struct {
name string
age int
score int
}
func (s *student12)sayhi() {
fmt.Printf("大家好我是%s,我今天%d岁,我这次考了%d分\n",s.name,s.age,s.score)
}
func (s *student12)sing(name string) {
fmt.Println("我为大家唱歌",name)
}
type teacher12 struct {
name string
age int
subject string
}
func (s *teacher12)sayhi() {
fmt.Printf("大家好我是%s,我今天%d岁,我这次教%s课",s.name,s.age,s.subject)
}
func main() {
//接口类型变量定义
var h Humaner1
var stu student12=student12{
name: "张三",
age: 20,
score: 20,
}
h=&stu
h.sayhi()
var p personer2
p=&stu
p.sayhi()
p.sing("wullllli")
//接口的转换 humaner1是子集,person2是超集,超集可以把值赋给子集,而反过来不行
}
空接口
接口类型可以接受任意类型的数据
var i []interface{}
接口类型的切片
类型断言
着重掌握第一种
- comma-ok断言
value,ok=element.(T)
value是变量的值(任意名字),ok是bool类型,element是interface变量,T是断言的类型
func main001() {
var i []interface{}
i= append(i,10,3.144545,"asdsad",tttttt)
for _,v := range i{
//fmt.Println(v)
if data,ok:=v.(int);ok{
fmt.Println("这是整型数据",data)
}else if data,ok:=v.(float64);ok{
fmt.Println("这是浮点数据",data)
}else if data,ok:=v.(string);ok{
fmt.Println("这是字符数据",data)
}else if data,ok:=v.(func());ok{
fmt.Println("这是函数数据",data)
}
}
}
- switch测试
func main(){
var i []interface{}
i= append(i,10,3.144545,"asdsad",tttttt)
for _,v := range i{
switch data:=v.(type) {
case int:
fmt.Println("整型数据",data)
case string:
fmt.Println("这是字符数据",data)
case float64:
fmt.Println("这是浮点数据",data)
case func():
fmt.Println("这是函数数据")
tttttt()
}
}
}