go语言基础--面向对象杂谈

面向过程

所谓的面向过程就是:强调的是步骤、过程、每一步都是自己亲自去实现的。

面向对象

所谓的面向对象其实就是找一个专门做这个事的人来做,不用关心具体怎么实现的。
所以说,面向过程强调的是过程,步骤。而面向对象强调的是对象,也就是干事的人。
在程序中,可以通过属性和方法(函数)来描述类。属性就是特征,方法(函数)就是行为。

面向对象编程好处

封装
继承
多态

继承

继承是一种类间关系,描述一个类从另一个类获取成员信息的类间关系。
继承必定发生在两个类之间,参与继承关系的双方称为父类和子类。
父类提供成员信息,子类获取成员信息。
通过匿名字段来实现继承
在这里插入图片描述

package mainimport "fmt"type Student struct {//属性---成员//方法---函数Person //匿名字段,只有类型,没有成员的名字score float64
}type Teacher struct {Person //匿名字段,只有类型,没有成员的名字salary float64
}type Person struct {id   intname stringage  int
}func main() {var stu Student = Student{Person{1, "张三", 18}, 98}fmt.Println(stu) //{{1 张三 18} 98}//部分初始化var stu1 Student = Student{score: 90}fmt.Println(stu1) //{{0  0} 90}var stu2 Student = Student{Person: Person{id: 101}} //{{101  0} 0}fmt.Println(stu2)
}

成员操作

package mainimport "fmt"type Student struct {//属性---成员//方法---函数Person //匿名字段,只有类型,没有成员的名字score float64
}type Person struct {id   intname stringage  int
}func main() {var stu Student = Student{Person{101, "张三", 18}, 98}var stu1 Student = Student{Person{102, "李四", 18}, 80}//获取成员的值fmt.Println(stu.score)      //98fmt.Println(stu1.score)     //80fmt.Println(stu1.Person.id) //102 //比较麻烦fmt.Println(stu1.id)        //102//修改成员的值stu.score = 100fmt.Println(stu.score) //100}

指针类型匿名字段

package mainimport "fmt"type Student struct {//属性---成员//方法---函数*Person //指针类型匿名字段score float64
}type Person struct {id   intname stringage  int
}func main() {var stu Student = Student{&Person{101, "张三", 18}, 98}fmt.Println(stu)      //{0xc000054460 98} 父类输出的是结构体内存地址 只能使用成员操作了fmt.Println(stu.name) //张三
}

多重继承—尽量不要写多重继承

package mainimport "fmt"// Student 学生继承person
type Student struct {//属性---成员//方法---函数Person //指针类型匿名字段score float64
}// Person 父类 person继承object
type Person struct {Object1name stringage  int
}type Object1 struct {id int
}func main() {var stu Studentstu.age = 18fmt.Println(stu.Person.age) //18stu.id = 101fmt.Println(stu.Person.Object1.id)
}

为结构体添加方法—封装

func  (对象 结构体类型) 方法名 (参数列表)(返回值列表) {代码体}

方法调用

对象名.方法

//不支持重载,只要接收者类型不一样,这个方法就算同名,也是不同方法,不会出现重复定义函数的错误

package mainimport "fmt"// Student
type Student struct {id   intname stringage  int
}// PrintShow 方法 s为接收者
func (s Student) PrintShow() {fmt.Println(s) //{101 ziye 18}
}func (s Student) EditInfo() {s.age = 20
}func (s *Student) EditInfo1() {s.age = 20
}
func main() {stu := Student{101, "ziye", 18}//对象名.方法名 把stu中的值传给了sstu.PrintShow() //完成对方法的调用stu.EditInfo()  //不是引用传递,是值传递stu.PrintShow()//内部会进行转换stu.EditInfo1() //引用传递stu.PrintShow() //{101 ziye 20}
}

注意事项

只要接收者类型不一样,这个方法就算同名,也是不同方法
接收者为指针类型

package mainimport "fmt"// Student
type Student struct {id   intname stringage  int
}type Teacher struct {id   intname string
}func (s *Student) show() {fmt.Println(s)
}func (t *Teacher) show() { //把teacher内存地址给到这里fmt.Println(t)
}
func main() {//如果接收者类型不同,即使方法的名字是相同的也是不同的方法stu := Student{101, "ziye", 18}stu.show() //等价于(&stu).show()teacher := Teacher{102, "ziyeye"}teacher.show()
}

面向对象方法练习

定义一个学生类,有六个属性,分别为姓名、性别、年龄、语文、数学、英语成绩
定义两个方法:

第一方法:打招呼的方法:介绍自己叫XX,今年几岁了。是男同学还是女同学。
第二个方法:计算总分与平均分的方法
package mainimport "fmt"// Student
type StudentInfo struct {name    string  //姓名sex     string  //性别age     int     //年龄chinese float64 //语文math    float64 //数学english float64 //英语
}// SayHello 打招呼
func (studentInfo *StudentInfo) SayHello(username string, userAge int, userSex string) {//初始化studentInfo.name = usernamestudentInfo.age = userAgestudentInfo.sex = userSex//初始化后的值进行判断if studentInfo.sex != "男" && studentInfo.sex != "女" {studentInfo.sex = "男"}if studentInfo.age < 1 || studentInfo.age > 100 {studentInfo.age = 18}//打印输出结果fmt.Printf("我叫%s,年龄是%d,性别是%s\n", studentInfo.name, studentInfo.age, studentInfo.sex)
}// GetScore 计算平均分
func (studentInfo *StudentInfo) GetScore(chinese float64, math float64, english float64) {//初始化studentInfo.chinese = chinesestudentInfo.math = mathstudentInfo.english = english//进行计算sum := studentInfo.chinese + studentInfo.math + studentInfo.english//打印输出结果fmt.Printf("我叫%s,总分%f,平均分%.2f\n", studentInfo.name, sum, sum/3)
}
func main() {var stu StudentInfostu.SayHello("ziye", 18, "女")stu.GetScore(98, 97, 95)
}

方法继承

package mainimport "fmt"// Student
type Student struct {Personscore float64
}type Person struct {id   intname string //姓名age  int    //年龄
}func (p *Person) PrintInfo() {fmt.Println(*p) //{101 张三 18}
}func main() {stu := Student{Person{101, "张三", 18}, 90}//子类可以调用父类的方法stu.PrintInfo()
}

方法继承的练习

根据以下信息,实现对应的继承关系

记者:我叫张三 ,我的爱好是偷拍,我的年龄是34,我是一个男狗仔。

程序员:我叫孙全,我的年龄是23,我是男生,我的工作年限是 3年。

  package mainimport "fmt"// Person 定义父类
type Person struct {name stringage  intsex  string
}// SetValue 给父类添加方法
func (p *Person) SetValue(userName string, userAge int, userSex string) {p.name = userNamep.age = userAgep.sex = userSex
}// Rep 定义相应的子类 记者类
type Rep struct {PersonHobby string //爱好
}// Pro 程序员类
type Pro struct {PersonWorkYear int
}// RepSayHello 给子类添加相应的信息
func (r *Rep) RepSayHello(Hobby string) {r.Hobby = Hobbyfmt.Printf("我叫%s ,我的爱好是%s,我的年龄是%d,我是一个%s狗仔\n", r.name, r.Hobby, r.age, r.sex)
}// ProSayHello 给子类添加相应的信息
func (p *Pro) ProSayHello(workYear int) {p.WorkYear = workYearfmt.Printf("我叫%s,我的年龄是%d,我是%s,我的工作年限是 %d年\n", p.name, p.age, p.sex, p.WorkYear)
}
func main() {var rep Reprep.SetValue("ziye", 34, "男")rep.RepSayHello("偷拍")var pro Propro.SetValue("李四", 26, "男")pro.ProSayHello(3)}

方法重写

就是子类(结构体)中的方法,将父类中的相同名称的方法的功能重新给改写了
注意:在调用时,默认调用的是子类中的方法

package mainimport "fmt"// Person 定义父类
type Person struct {name stringage  int
}func (p *Person) PrintInfo() {fmt.Println("这是父类中的方法")
}type Student struct {Personscore float64
}func (s *Student) PrintInfo() {fmt.Println("这是子类中的方法")
}func main() {var stu Studentstu.PrintInfo() //这是子类中的方法 如果父类中的方法名称与子类中的方法一致,那么通过子类的对象调用的是子类中的方法,方法重写stu.Person.PrintInfo() //这是父类中的方法 调用父类中的方法
}

方法值与方法表达式

package mainimport "fmt"// Person 定义父类
type Person struct {name stringage  int
}func (p *Person) PrintInfo() {fmt.Println(*p) //{ziye 18}
}func main() {per := Person{"ziye", 18}per.PrintInfo()//方法值f := per.PrintInfofmt.Printf("%T\n", f) //func() 方法类型f()                   //{ziye 18}//方法表达式f1 := (*Person).PrintInfo //并没有指定一个对象 类名要和方法接收者类型保存一致f1(&per)                  //{ziye 18} 方法表达式
}

接口简介

接口就是一种规范与标准,只是规定了要做哪些事情。具体怎么做,接口是不管的。
接口把所有的具有共性的方法定义在一起,任何其他类型只要实现了这些方法就是实
现了这个接口。

接口定义

type 接口名字 interface {

方法声明

}

接口的声明

可以为结构体添加接口中的方法,完成接口中方法实现

package mainimport "fmt"// Personer 接口的声明
type Personer interface {SayHello() //方法声明
}type Student struct {
}// SayHello 使用student完成SayHello
func (s *Student) SayHello() {fmt.Println("老师好")
}type Teacher struct {
}func (t *Teacher) SayHello() {fmt.Println("学生好")
}func main() {//对象名.方法名var stu Studentstu.SayHello() //老师好var teacher Teacherteacher.SayHello() //学生好//接口变量来调用,必须都实现接口中所声明的方法var person Personerperson = &stuperson.SayHello() //调用的是Student、实现的SayHello方法 老师好person = &teacherperson.SayHello() //学生好}

多态的定义与实现

什么是多态

所谓多态:指的是多种表现形式。
多态就是同一个接口,使用不同的实例而执行不同操作

package mainimport "fmt"type Personer interface {SayHello()
}type Student struct {
}func (s *Student) SayHello() {fmt.Println("老师好")
}type Teacher struct {
}func (t *Teacher) SayHello() {fmt.Println("学生好")
}//实现多态
func WhoSayHi(personer Personer) {personer.SayHello()
}func main() {var stu Studentvar teacher TeacherWhoSayHi(&stu)WhoSayHi(&teacher)
}

案例

用多态来模拟实现 将移动硬盘或者U盘插到电脑上进行读写数据

package mainimport "fmt"type Stroager interface {Read()Writer()
}// MDisk 移动硬盘
type MDisk struct {
}func (m *MDisk) Read() {fmt.Println("移动硬盘读取数据")
}func (m *MDisk) Writer() {fmt.Println("移动硬盘写入数据")
}// UDisk U盘
type UDisk struct {
}func (u *UDisk) Read() {fmt.Println("U盘读取数据")
}func (u *UDisk) Writer() {fmt.Println("U盘写入数据")
}// Computer 定义一个函数
func Computer(s Stroager) {s.Writer()s.Read()
}
func main() {var uds UDiskvar mds MDiskComputer(&uds)Computer(&mds)
}

案例

使用面向对象方式,实现一个计算器程序

案例实现一


package mainimport "fmt"type Object1 struct {
}func (o *Object1) GetResult(num1, num2 int, op string) int {//添加参数var result intswitch op {case "+":result = num1 + num2case "-":result = num1 - num2}return result
}func main() {var obj Object1result := obj.GetResult(8, 6, "+")fmt.Println(result)
}

案例实现二

package mainimport "fmt"// 加法类
type Add struct {Object1
}func (add *Add) GetResult() int { //方法的实现要和接口中方法的声明保持一致return add.numA + add.numB
}type Sub struct {Object1
}func (sub *Sub) GetResult() int {return sub.numA - sub.numB
}type Object1 struct {numA intnumB int
}type Resulter interface {GetResult() int //返回类型int
}func main() {add := Add{Object1{10, 8}}result := add.GetResult()fmt.Println(result)sub := Sub{Object1{10, 8}}result = sub.GetResult()fmt.Println(result)
}

案例实现三

package mainimport "fmt"// 加法类
type Add struct {Object1
}func (add *Add) GetResult() int { //方法的实现要和接口中方法的声明保持一致return add.numA + add.numB
}type Sub struct {Object1
}func (sub *Sub) GetResult() int {return sub.numA - sub.numB
}type Object1 struct {numA intnumB int
}type Resulter interface {GetResult() int //返回类型int
}// OperatorFactory 对象创建问题
// 1:定义一个新的类
type OperatorFactory struct {
}// CreaeteOperator 创建一个方法,在该方法中完成对象的创建----封装
func (o *OperatorFactory) CreaeteOperator(op string, numA, numB int) int {switch op {case "+":add := Add{Object1{numA, numB}}return OperatorWho(&add)case "-":sub := Sub{Object1{numA, numB}}return OperatorWho(&sub)default:return 0}
}
// 多态
func OperatorWho(h Resulter) int {result := h.GetResult()return result
}
func main() {var operator OperatorFactorycreaeteOperator := operator.CreaeteOperator("+", 20, 10)fmt.Println(creaeteOperator)
}

接口的继承与转换

package mainimport "fmt"type Humaner interface {SayHello()
}// Personer 接口继承
type Personer interface {HumanerSay()
}
type Student struct {
}func (s *Student) SayHello() {fmt.Println("大家好")
}func (s *Student) Say() {fmt.Println("你好")
}func main() {var Stu Studentvar per Personerper = &Stuper.Say()per.SayHello() //可以调用所继承的接口中的方法//接口转换var h Humanerh = perh.SayHello()//超集可以转换为子集,反过来不可以//per = h
}

空接口定义与使用

var i interface{} //空接口
i = 123
fmt.Println(i)

空接口可以赋任意的类型,切片s可以赋值各种类型的

var s []interface{} //空接口切片ss = append(s, 123, "abc", 23.12)for i := 0; i < len(s); i++ {fmt.Println(s[i])}

空接口(interface{})不包含任何的方法,正因为如此,所有的类型都实现了空接口,因此空接口可以存储任意类型的数值

类型断言

通过类型断言,可以判断空接口中存储的数据类型。
语法:value, ok := m.(T)
m:表空接口类型变量
T:是断言的类型
value: 变量m中的值。
ok: 布尔类型变量,如果断言成功为true,否则为false

package mainimport "fmt"func main() {var i interface{}i = 123value, ok := i.(int)if ok {fmt.Println(value)} else {fmt.Println("类型推断错误")}
}

案例–空接口与类型断言综合应用

计算器,完成数据校验

package mainimport "fmt"// 加法类
type Add struct {Object1
}func (add *Add) GetResult() int { //方法的实现要和接口中方法的声明保持一致return add.numA + add.numB
}func (add *Add) SetData(data ...interface{}) bool {//对数据的个数进行校验var b bool = trueif len(data) > 2 || len(data) <= 1 {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}add.numA = valueadd.numB = value1//对传递过来的类型进行校验return b
}type Sub struct {Object1
}func (sub *Sub) GetResult() int {return sub.numA - sub.numB
}
func (sub *Sub) SetData(data ...interface{}) bool {//对数据的个数进行校验var b bool = trueif len(data) > 2 || len(data) <= 1 {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}sub.numA = valuesub.numB = value1//对传递过来的类型进行校验return b
}type Object1 struct {numA intnumB int
}type Resulter interface {GetResult() int                   //返回类型intSetData(data ...interface{}) bool //完成参数运算的数据的类型校验
}// OperatorFactory 对象创建问题
// 1:定义一个新的类
type OperatorFactory struct {
}// CreaeteOperator 创建一个方法,在该方法中完成对象的创建----封装
func (o *OperatorFactory) CreaeteOperator(op string) Resulter {switch op {case "+":add := new(Add) //返回*addreturn addcase "-":sub := new(Sub) //创建Sub 开辟相应的存储空间return subdefault:return nil}
}// 多态
func OperatorWho(h Resulter) int {result := h.GetResult()return result
}
func main() {var operator OperatorFactorycreaeteOperator := operator.CreaeteOperator("-") //拿到对象setData := creaeteOperator.SetData(30, 10)if setData {who := OperatorWho(creaeteOperator)fmt.Println(who)}}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/81376.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

C++编译过程

文章目录 1、c编译 1、c编译 鼠标右键选择“Open in Integrated Terminal”&#xff0c;然后在下面的终端输入“cmake . -B build”&#xff0c;或者是这个命令也可以“cmake --build build -j12”&#xff0c;完成之后再次在终端输入“cmake --build build”&#xff0c;完成之…

2023Web前端逻辑面试题

1、现有9个小球&#xff0c;已知其中一个球比其它的重&#xff0c;如何只用天平称2次就找出该球&#xff1f; ①把9个球分成三份&#xff0c;三个一份&#xff1b; ②拿出其中两份进行称量&#xff1b;会分为两种情况 若拿出的两份小球称量结果&#xff0c;重量相等&#xff1b…

使用香橙派 学习Linux的串口开发

串口的回顾 & 硬件接线 关于串口也是之前学习过很多次了&#xff0c;详见&#xff1a; 认识串口 和 蓝牙模块HC08_hc08蓝牙模块_mjmmm的博客-CSDN博客 串口的再认识-CSDN博客 香橙派提供了两路串口&#xff0c;第一路就是在刷机时串口连接的引脚&#xff08;对应驱动ttyS0&…

MAC MINI 2012安装Montery折腾笔记

MAC MINI 2012安装Montery折腾笔记&#xff08;作为电视盒子/远程开发机&#xff09; 起因&#xff1a; 手头有个mac mini&#xff0c;2018年买的2手。一直都是10.12系统&#xff0c;处理python和苹果开发都受制于旧系统&#xff0c;很多软件也装不上&#xff0c;于是有了升级…

python有限差分法求解一维热传导方程

​1、方程及其离散 1.1一维热传导方程 1.2离散化 设定步长&#xff0c;依据上述方程得到递推关系&#xff1a; 2、python求解实现 import numpy as np import matplotlib.pyplot as plth 0.1#空间步长 N 30#空间步数 dt 0.0001#时间步长 M 10000#时间的步数 A dt/(h**2)…

Java8实战-总结29

Java8实战-总结29 并行数据处理与性能并行流将顺序流转换为并行流测量流性能 并行数据处理与性能 到目前为止&#xff0c;Stream接口最重要的好处是可以对这些集合执行操作流水线&#xff0c;能够自动利用计算机上的多个内核。 例如&#xff0c;在Java 7之前&#xff0c;并行…

如何开发你的第一个Vue.js插件:完整指南

&#x1f337;&#x1f341; 博主猫头虎&#xff08;&#x1f405;&#x1f43e;&#xff09;带您 Go to New World✨&#x1f341; &#x1f984; 博客首页——&#x1f405;&#x1f43e;猫头虎的博客&#x1f390; &#x1f433; 《面试题大全专栏》 &#x1f995; 文章图文…

ModbusTCP服务端

1在Device下&#xff0c;添加设备net&#xff1a; 公交车。 2在net下添加 ModbusTCP

【深度学习】 Python 和 NumPy 系列教程(十九):Matplotlib详解:2、3d绘图类型(5)3D等高线图(3D Contour Plot)

目录 一、前言 二、实验环境 三、Matplotlib详解 1、2d绘图类型 2、3d绘图类型 0. 设置中文字体 1. 3D线框图&#xff08;3D Line Plot&#xff09; 2. 3D散点图&#xff08;3D Scatter Plot&#xff09; 3. 3D条形图&#xff08;3D Bar Plot&#xff09; 4. 3D曲面图…

MySQL数据库详解 三:索引、事务和存储引擎

文章目录 1. 索引1.1 索引的概念1.2 索引的作用1.3 如何实现索引1.4 索引的缺点1.5 建立索引的原则依据1.6 索引的分类和创建1.6.1 普通索引1.6.2 唯一索引1.6.3 主键索引1.6.4 组合索引1.6.5 全文索引 1.7 查看索引1.8 删除索引 2. 事务2.1 事务的概念2.2 事务的ACID特性2.2.1…

人机中的事实与价值时空、排序

人机结合智能与事实价值融合分析确实是未来解决复杂疑难问题的基本策略之一。该策略利用人类智慧和机器智能相结合&#xff0c;结合有效的事实和价值分析方法&#xff0c;以更全面、准确、高效地解决问题。 通过人机结合&#xff0c;可以充分发挥人类的主观能动性、判断力和创造…

2023年 python结合excel实现快速画图(零基础快速入门)

目录 1.适用人群 2.环境配置 3.基本用法 3.1 数据读取 3.2 数据分析 3.3 数据组装 3.4 制表&#xff1a; 4.快速提升 5.效果展示 1.适用人群 电脑有python环境&#xff0c;会python基本使用&#xff0c;需要短时间内完成大量画图任务的数据分析的人群。&#xff08;有…

JDK17特性

文章目录 一、JAVA17概述二、语法层面的变化1.密封类2.switch模式匹配&#xff08;预览&#xff09; 三、API层面变化1.Vector API&#xff08;第二个孵化器&#xff09;2.特定于上下文的反序列化过滤器 四、其他变化1.恢复始终严格的浮点语义2.JEP 增强型伪随机数生成器3.JEP …

C++库函数——map与set

目录 1.关联式容器是什么&#xff1f; 2.键值对 3.set ①set的介绍 ②set的模板参数列表 ③set的构造 ④set的迭代器 ⑤set的容量 ⑥set的修改与操作 ⑦set的使用举例 4.multiset ①multiset的介绍 ②multiset的使用举例 5.map ①map的介绍 ②map的模版参数列表…

HuggingFace Transformer

NLP简介 HuggingFace简介 hugging face在NLP领域最出名&#xff0c;其提供的模型大多都是基于Transformer的。为了易用性&#xff0c;Hugging Face还为用户提供了以下几个项目&#xff1a; Transformers(github, 官方文档): Transformers提供了上千个预训练好的模型可以用于不…

基于讯飞人脸算法(调用API进行人脸比对)

先看结果 必须遥遥领先 所需准备 这里我调用了&#xff1a; 人脸比对 API 文档 | 讯飞开放平台文档中心https://www.xfyun.cn/doc/face/xffaceComparisonRecg/API.html#%E6%8E%A5%E5%8F%A3%E8%AF%B4%E6%98%8E 代码里所涉及的APPID、APISecret、APIKey 皆从讯飞的控制台获取&…

市场,只能被操纵,不能被战胜

所谓市场&#xff0c;不过是千千万参与主体各自独立意志、自主行动所形成的复杂混沌的互动结果。价格&#xff0c;则是这一复杂混沌系统的涌现现象。 无数在市场中追风打浪的人&#xff0c;总是梦想着自己有朝一日能够战胜市场&#xff0c;获得超额回报。于是他们绞尽脑汁&…

Mybatis学习笔记3 在Web中应用Mybatis

Mybatis学习笔记2 增删改查及核心配置文件详解_biubiubiu0706的博客-CSDN博客 技术栈:HTMLServletMybatis 学习目标: 掌握mybatis在web应用中如何使用 Mybatis三大对对象的作用域和生命周期 关于Mybatis中三大对象的作用域和生命周期、 官网说明 ThreadLocal原理及使用 巩…

JAVA入坑之嵌套类

一、嵌套类入门 1.1概述 Java嵌套类是指在一个类中定义另一个类的一种方式&#xff0c;它可以提高代码的可读性、可维护性和封装性。Java嵌套类分为两种类型&#xff1a;静态嵌套类和非静态嵌套类。 静态嵌套类&#xff1a;Static nested classes,即类前面有static修饰符 非静…

【论文解读】Faster sorting algorithm

一、简要介绍 基本的算法&#xff0c;如排序或哈希&#xff0c;在任何一天都被使用数万亿次。随着对计算需求的增长&#xff0c;这些算法的性能变得至关重要。尽管在过去的2年中已经取得了显著的进展&#xff0c;但进一步改进这些现有的算法路线的有效性对人类科学家和计算方法…