type Student struct{
Person // 匿名字段,,只有类型,没有成员的名字
score float64}type Teacher struct{
Person
salary float64}type Person struct{
id int
name string
age int}funcmain(){var stu Student = Student{Person{101,"张三",18},90}// 部分初始化var stu1 Student = Student{score:90}var stu2 Student = Student{Person: Person{id:101}}
fmt.Println(stu)// {{101 张三 18} 90}
fmt.Println(stu1)// {{0 0} 90}
fmt.Println(stu2)// {{101 0} 0}}
2 - 成员操作
成员的操作包含:
获取成员的值:对象名.成员
修改成员的值:对象名.成员 = 值
type Student struct{
Person
score float64}type Person struct{
id int
name string
age int}funcmain(){var stu Student = Student{Person{101,"张三",18},90}var stu1 Student = Student{Person{102,"李四",18},80}
stu.score =100
fmt.Println("张三考试成绩:", stu.score)
fmt.Println(stu1.score)
fmt.Println(stu1.Person.id)
fmt.Println(stu1.id)//简化写法,先到子类中查找成员,没有找到成员后就到父类中查找}
3 - 指针匿名字段
type Student struct{*Person // 匿名字段
score float64}type Person struct{
id int
name string
age int}funcmain(){var stu Student = Student{&Person{101,"张三",18},90}
fmt.Println(stu.name)}
4 - 多重继承
type Student struct{
Person
score float64}type Person struct{
Object
name string
age int}type Object struct{
id int}funcmain(){var stu Student
stu.age =18
fmt.Println(stu.Person.age)
stu.id =101
fmt.Println(stu.Person.Object.id)}
5 - 为结构体添加方法
一般都将方法的接收对象使用结构体指针来接收
//语法func(对象 结构体类型) 方法名 (参数列表)(返回值列表){
代码体
}//案例type Student struct{
id int
name string
age int}func(s Student)PrintShow(){
fmt.Println(s)}func(s *Student)EditInfo(){//如果不是结构体指针,将无法修改原对象的值
s.age =20}funcmain(){
stu := Student{101,"张三",18}
stu.PrintShow()// 完成对方法的调用, 将stu中的值,传递给了方法的s
stu.EditInfo()
stu.PrintShow()}
只要接收者类型不一样,这个方法就算同名,也是不同方法
type Student struct{
id int
name string
age int}type Teacher struct{
id int
name string}func(s *Student)Show(){
fmt.Println(s)}func(t *Teacher)Show(){
fmt.Println(t)}funcmain(){// 如果接收者类型不同,即使方法的名字是相同的也是不同的方法
stu := Student{101,"李四",18}(&stu).Show()
stu.Show()// 这个是go语言的优化,实际是(&stu).Show()
teacher := Teacher{102,"老王"}
teacher.Show()}
案例:获取学生信息
//定义一个学生类,有六个属性,分别为姓名、性别、年龄、语文、数学、英语成绩//第一方法:打招呼的方法:介绍自己叫XX,今年几岁了。是男同学还是女同学。//第二个方法:计算总分与平均分的方法// 1: 定义结构体type StudentInfo struct{
name string
sex string
age int
chinese float64
math float64
english float64}// 2: 添加方法func(s *StudentInfo)SayHello(userName string, userAge int, userSex string){// 2.1 初始化
s.name = userName
s.age = userAge
s.sex = userSex
// 2.2 初始化后的值进行判断。if s.sex !="男"&& s.sex !="女"{
s.sex ="男"}if s.age <1|| s.age >100{
s.age =18}// 2.3 打印输出结果
fmt.Printf("我叫%s,年龄是%d,性别是%s\n", s.name, s.age, s.sex)}func(s *StudentInfo)GetScore(chinese float64, math float64, english float64){// 1: 初始化
s.chinese = chinese
s.math = math
s.english = english
// 2: 进行计算
sum := s.chinese + s.math + s.english
// 3: 打印输出结果
fmt.Printf("我叫%s,总分%f,平均分%f", s.name, sum, sum/3)}funcmain(){var stu StudentInfo
stu.SayHello("张三",180,"df")
stu.GetScore(90,89,87)}
三、方法继承与重写
方法继承:子类可以调用父类的方法
type Student struct{
Person
score float64}type Person struct{
id int
name string
age int}func(p *Person)PrintInfo(){
fmt.Println(*p)}funcmain(){
stu := Student{Person{101,"张三",18},90}
stu.PrintInfo()}
方法重写:默认调用的是子类中的方法
如果父类中的方法名称与子类中的方法名称一致,那么通过子类的对象调用的是子类中的方法
子类方法重写,要调用父类的方法stu.Person.PrintInfo()
type Person struct{
name string
age int}func(p *Person)PrintInfo(){
fmt.Println("这是父类中的方法")}type Student struct{
Person
score float64}func(p *Student)PrintInfo(){
fmt.Println("这是子类中的方法")}funcmain(){var stu Student
stu.PrintInfo()// 如果父类中的方法名称与子类中的方法名称一致,那么通过子类的对象调用的是子类中的方法;方法重写
stu.Person.PrintInfo()}
方法值与方法表达式:实现方法调用
type Person struct{
name string
age int}func(p *Person)PrintInfo(){
fmt.Println(*p)}funcmain(){
per := Person{"张三",18}
per.PrintInfo()//方法值
f := per.PrintInfo
fmt.Printf("%T", f)f()//方法表达式
f1 :=(*Person).PrintInfo
f1(&per)}
四、接口
什么是接口:
接口就是一种规范与标准,只是规定了要做哪些事情。具体怎么做,接口是不管的
接口把所有的具有共性的方法定义在一起,任何其他类型只要实现了这些方法就是实现了这个接口
接口定义语法
type 接口名字 interface{
方法声明
}
接口实现与调用
type Personer interface{SayHello()}type Student struct{}func(s *Student)SayHello(){
fmt.Println("老师好")}type Teacher struct{}func(t *Teacher)SayHello(){
fmt.Println("学生好")}funcmain(){// 对象名.方法名var stu Student
stu.SayHello()var teacher Teacher
teacher.SayHello()// 通过接口变量来调用,必须都实现接口中所声明的方法var person Personer
person =&stu
person.SayHello()// 调用的是Student 实现的SayHello方法
person =&teacher
person.SayHello()}
五、多态
多态概念:指的是多种表现形式;多态就是同一个接口,使用不同的实例而执行不同操作
多态实现语法:定义函数实现
func 函数名 (参数 接口类型){}
多态定义与实现
type Personer interface{SayHello()}type Student struct{}func(s *Student)SayHello(){
fmt.Println("老师好")}type Teacher struct{}func(t *Teacher)SayHello(){
fmt.Println("学生好")}funcWhoSayHi(h Personer){
h.SayHello()}funcmain(){var stu Student
var teacher Teacher
WhoSayHi(&stu)WhoSayHi(&teacher)}
type Object struct{}// 2: 添加一个方法。func(o *Object)GetResult(numA int, numB int, op string)int{// 1: 添加参数// 2: 判断运算方式var result intswitch op {case"+":
result = numA + numB +100case"-":
result = numA - numB -100}return result
}funcmain(){var obj Object
num := obj.GetResult(8,6,"-")
fmt.Println(num)}
案例:分离类方式实现计算器
// 加法类type Add struct{
Object
}func(a *Add)GetResult()int{// 方法的实现要和接口中方法的声明保持一致return a.numA + a.numB
}// 减法类type Sub struct{
Object
}func(s *Sub)GetResult()int{return s.numA - s.numB
}type Object struct{
numA int
numB int}type Resulter interface{GetResult()int}funcmain(){
add := Add{Object{10,20}}
num := add.GetResult()
fmt.Println(num)
sub := Sub{Object{20,10}}
num1 := sub.GetResult()
fmt.Println(num1)}
案例:工厂创建对象方式实现计算器
// 加法类type Add struct{
Object
}func(a *Add)GetResult()int{// 方法的实现要和接口中方法的声明保持一致return a.numA + a.numB
}// 减法类type Sub struct{
Object
}func(s *Sub)GetResult()int{return s.numA - s.numB
}type Object struct{
numA int
numB int}type Resulter interface{GetResult()int}// 对象问题// 1: 定义一个新的类type OperatorFactory struct{}// 2: 创建一个方法,在该方法中完成对象的创建func(o *OperatorFactory)CreateOperator(op string, numA int, numB int)int{switch op {case"+":
add := Add{Object{numA, numB}}returnOperatorWho(&add)case"-":
sub := Sub{Object{numA, numB}}returnOperatorWho(&sub)default:return0}}funcOperatorWho(h Resulter)int{return h.GetResult()}funcmain(){var operator OperatorFactory
num := operator.CreateOperator("-",20,10)
fmt.Println(num)}
六、接口的继承与转换
type Humaner interface{SayHello()}type Personer interface{
Humaner
Say()}type Student struct{}func(s *Student)SayHello(){
fmt.Println("大家好")}func(s *Student)Say(){
fmt.Println("你好")}funcmain(){var stu Student
var per Personer
per =&stu
per.Say()
per.SayHello()// 可以调用所继承的接口中的方法var h Humaner
h = per
h.SayHello()}
funcmain(){var i interface{}// i就是一个空接口类型的变量
i =123
i ="abc"
fmt.Println(i)var s []interface{}// 空接口类型的切片
s =append(s,123,"abc",12.3)for j :=0; j <len(s); j++{
fmt.Println(s[j])}}
类型断言:通过类型断言,可以判断空接口中存储的数据类型
类型断言语法:value, ok := m.(T)
m:表空接口类型变量
T:是断言的类型.
value: 变量m中的值
ok: 布尔类型变量,如果断言成功为true,否则为false
funcmain(){var i interface{}
i ="abc"
value, ok := i.(int)if ok {
fmt.Println(value +10)}else{
fmt.Println("类型推断错误")}}
案例:空接口与类型断言实现计算器数据校验
package main
import"fmt"// 加法类type Add struct{
Object
}func(a *Add)GetResult()int{// 方法的实现要和接口中方法的声明保持一致return a.numA + a.numB
}func(a *Add)SetData(data ...interface{})bool{// 1: 对数据的个数进行校验。var b bool=trueiflen(data)>2{
fmt.Println("参数个数错误!!")
b =false}
value, ok := data[0].(int)if!ok {
fmt.Println("第一个数类型错误")
b =false}
value1, ok1 := data[1].(int)if!ok1 {
fmt.Println("第二个数据类型错误")
b =false}
a.numA = value
a.numB = value1
// 2: 类型进行校验。return b
}// 减法类type Sub struct{
Object
}func(s *Sub)GetResult()int{return s.numA - s.numB
}func(s *Sub)SetData(data ...interface{})bool{// 1: 对数据的个数进行校验。var b bool=trueiflen(data)>2{
fmt.Println("参数个数错误!!")
b =false}
value, ok := data[0].(int)if!ok {
fmt.Println("第一个数类型错误")
b =false}
value1, ok1 := data[1].(int)if!ok1 {
fmt.Println("第二个数据类型错误")
b =false}
s.numA = value
s.numB = value1
// 2: 类型进行校验。return b
}type Object struct{
numA int
numB int}type Resulter interface{GetResult()intSetData(data ...interface{})bool// 完成参数运算的数据的类型校验。}// 对象问题// 1: 定义一个新的类type OperatorFactory struct{}// 2: 创建一个方法,在该方法中完成对象的创建func(o *OperatorFactory)CreateOperator(op string) Resulter {switch op {case"+":
add :=new(Add)return add
case"-":
sub :=new(Sub)return sub
default:returnnil}}funcOperatorWho(h Resulter)int{return h.GetResult()}funcmain(){var operator OperatorFactory
obj := operator.CreateOperator("-")
b := obj.SetData(30,10)if b {
num :=OperatorWho(obj)
fmt.Println(num)}}