Go语言流处理,工厂模式,命令参数,序列化,单元测试

news2025/6/9 4:55:54

IO流

流就是数据在数据源和程序之间经历的路径。数据源可以是文件数据库或者键盘输入等,程序是运行在内存中的应用。

数据从数据源输入到程序的路径为输入流,从内存输出到数据源的路径为输出流。

在这里插入图片描述

流是以内存为核心,输入到内存就是输入流,将数据内存持久化就是输出流。

计算机中的流其实是一种信息的转换。它是一种有序流,因此相对于某一对象,通常我们把对象接收外界的信息输入(Input)称为输入流,相应地从对象向外输出(Output)信息为输出流,合称为输入/输出流(I/O Streams)。对象间进行信息或者数据的交换时总是先将对象或数据转换为某种形式的流,再通过流的传输,到达目的对象后再将流转换为对象数据。所以,可以把流看作是一种数据的载体,通过它可以实现数据交换和传输。

针对计算机来说流的基本单位为字节流,而对程序来说,程序还可以识别字符流。字节流是面向计算机的,字符流是面向应用的。

程序也是通过流与计算机实现数据交换,一般编程语言都提供了内置的流(I/O)接口。

Java I/O

alt

Go I/O
在这里插入图片描述
在这里插入图片描述

在计算机软件工作的过程成需要大量使用I/O,例如软件的本地数据库,存储了用户的缓存信息等,流是数据持久化的桥梁。将程序中即内存中的数据写入到显示器或者写入到文件系统。

键盘的输入输出

//输出
fmt.Println()   //打印换行
fmt.Print()     //打印
fmt.Printf()    //格式化打印


//输入
fmt.Scanf()
fmt.Scanln()
fmt.Scan()

格式化输入输出(一般带f)

%v 值的默认格式表示
%T 值的类型的Go语法表示
%t 单词true或false
%d 表示为十进制
%f 有小数部分但无指数部分,如123.456
%s 直接输出字符串或者[]byte

fmt.Printf(format string, a ...interface{}) (n int, err error)

var a = "test"
var b = Student{} 
var c = "10"
fmt.Printf("默认输出%v,类型输出%T,十进制输出%d,字符输出%s", a, b, c, a)

在这里插入图片描述

fmt.Scanf(format string, a ...any) (n int, err error)

在格式化输入时,需要注意以下几点:

  1. 输入的格式和书写的格式要一致,在格式化符处对应即可
  2. 输入时必须用地址接收,节约内存
  3. 书写时格式化符没有用标点符号隔开的,输入是默认用空格隔开
//3特性
var a1 int
var b1 string
fmt.Scanf("%d,%s\n", &a1, &b1)
fmt.Scanf("%d%s\n", &a1, &b1)

输入时第一个用”,“隔开,第二个用空格隔开。

//特性1
fmt.Scanf("a=%d,b=%s\n", &a1, &b1)
fmt.Scanf("输入一个十进制数%d,输入一个字符串%s\n", &a1, &b1)

在这里插入图片描述
在这里插入图片描述

标准输入输出

func Println(a ...interface{}) (n int, err error)

a1 := 10
b1 := "qwe"
fmt.Println(a1, b1)

在这里插入图片描述
Println方法标准化输出时相邻参数的输出之间添加空格并在输出结束后添加换行符,Print不会自动换行。

func Scan(a ...interface{}) (n int, err error)

Scan从标准输入扫描文本,将成功读取的空白分隔的值保存进成功传递给本函数的参数。(注意只能用空格隔开输入,在书写也只能用”,“隔开变量地址接收)

var a1 int
var b1 string
fmt.Scan(&a1,&b1)
fmt.Print(a1, b1)

在这里插入图片描述
Scanln方法能自动换行。

fmt包其他格式化I/O,详见中文开发手册

文件操作

file, err := os.Open("D:\\Go\\Go Files\\unit5\\src\\test\\hello.txt")
//file, err := os.Open("D:/Go/Go Files/unit5/src/test/hello.txt")
//file, err := os.Open("../test/hello.txt")
if err != nil {
	fmt.Println("file nnot found")
	return
}
defer file.Close()

reader := bufio.NewReader(file)

for {
	str, err := reader.ReadString('\n')
	if err == io.EOF {
		break
	}

	fmt.Print(str)
}

对于Go来说没有严格的/\\区分,均可以读取。

filebyte, err := ioutil.ReadFile("D:\\Go\\Go Files\\unit5\\src\\test\\hello.txt")
if err != nil {
	fmt.Println("read file err=", err)
}
fmt.Printf("%v", string(filebyte))
  • 创建文件并写文件
filepath := "./abc.txt"
file, err := os.OpenFile(filepath, os.O_RDONLY|os.O_CREATE, 0666)
if err != nil {
	fmt.Printf("open file err=%v\n", err)
	return
}

defer file.Close()

str := "hello,gardon\n"

writer := bufio.NewWriter(file)
//循环写入几行
for j := 0; j < len(str); j++ {
	writer.WriteString(str)
}

writer.Flush()

工厂模式

在Go语言中,一条件下某些结构体并不需要多次创建,只需要单一的实例即可即工厂模式或者单例模式。例如在数据的datasource创建时的工厂模式单例即可。

在Go语言中,没有像Java的static关键字,如需要单例模式只需要通过指针来操作即可,即返回变量的地址。

package main

import "fmt"

func main() {
	//
	var student = StudentFactory(1, "xuwenhui")
	fmt.Println((*student).id, (*student).name)
}

type student struct {
	id   int
	name string
}

func StudentFactory(id int, name string) *student {
	return &student{
		id:   id,
		name: name,
	}
}

在上面代码中student结构体要设为单例模式,需要设置访问权限,通过公开访问方法StudentFactory返回结构体的地址,并用指针操作结构体,实现工厂模式。

类型断言

在Go的多态特性中,不同的特性需要使用断言来调用不同的方法。

type Person struct {
	name string
	sex  string
}

type Student struct {
	person Person
	sid    string
}

// 需要一个父类是两个结构体的父接口
// 空接口是任何类型的父类
type Per interface {
}

在上述代码中需要一个参数能同时接收Person和Student类,同时调用其方法,Go语言中,通过断言来决策。

断言能够将子类用父类接收实现多态性,具体用法是变量.(类型)

func main() {
	var a Per
	var b = a.(Person)
	fmt.Println(b.name, b.sex)

	var c = a.(Student)
	fmt.Println(c.person.name, c.person.sex, c.sid)
}

type Person struct {
	name string
	sex  string
}

type Student struct {
	person Person
	sid    string
}

// 需要一个父类是两个结构体的父接口
// 空接口是任何类型的父类
type Per interface {
}

在上面代码中通过断言将a接口转化为任意类型(Person和Student)。使用断言可以将任意已知类型转化,并调用转化后的成员与方法。

package main

import "fmt"

func main() {
	// var a Per
	// var b = a.(Person)
	// fmt.Println(b.name, b.sex)
	// b.showPn()

	// var c = a.(Student)
	// fmt.Println(c.person.name, c.person.sex, c.sid)
	// c.showStu()

	stu1 := Student{
		person: Person{
			"xu",
			"nan",
		},
		sid: "s001",
	}

	identufy(stu1)

}

type Person struct {
	name string
	sex  string
}

func (pn Person) showPn() {
	fmt.Println(pn.name, pn.sex)
}

type Student struct {
	person Person
	sid    string
}

func (stu Student) showStu() {
	fmt.Println(stu.person.name, stu.person.sex, stu.sid)
}

// 需要一个父类是两个结构体的父接口
// 空接口是任何类型的父类
type Per interface {
}

func identufy(per Per) {
	//通过断言做类的变换
	var x = per.(Student)
	fmt.Println(x.person.name, x.person.sex, x.sid)
	x.person.showPn()
	x.showStu()

}

在上面代码中identufy方法接收Per的参数,使用断言将参数转化为已指对象Student,就可以使用其成员与方法。同时也可以接收Person参数,或者接收任意已知类型。

命令参数

在多环境开发的情况下,需要更改环境便于测试,因为不同的环境配置不一样,在代码内部可以直接通过读取不同的配置文件来实现,但是当代码打包后就无法通过更改代码来实现了,需要通过外部的参数。

Go的os命令提供了os.Args切片来存储所有命令行参数。

import (
	"fmt"
	"os"
)

func main() {

	//输出命令行参数长度
	fmt.Println("命令行参数长度", len(os.Args))
	//循环输出参数
	for index, value := range os.Args {
		fmt.Printf("args[%v]=%v\n", index, value)
	}

}

在这里插入图片描述

需要注意的是参数以空格分离。

命令参数解析

flag包实现了命令行参数的解析。

os.Args可以满足一些基本的参数要求,但是复杂的在使用改参数就不太方便了,Go也提供了flag包实现了命令行参数的解析。

var usr, pwd, host string
var port int

flag.StringVar(&usr, "user", "", "用户名")
flag.StringVar(&pwd, "password", "", "密码")
flag.StringVar(&host, "h", "localhost", "主机名")
flag.IntVar(&port, "port", 3306, "端口")

flag.Parse()

fmt.Printf("usr=%s,pwd=%s,host=%s,port=%d", usr, pwd, host, port)

flag的var系列的函数将参数绑定到指定的变量上,通过变量输入没有顺序要求。var系列函数有一般有四个参数第一参数为程序的变量,第二个参数为绑定输入变量参数,第三个为默认值,第四个参数为绑定参数描述。

命令行输入时通过-绑定参数 数值输入。

在这里插入图片描述

序列化与反序列化

序列化

Go语言对JSON操作的包均在encoding/json包下,包下提供了Marshal方法来序列化Go内置对象。Marshal函数返回v的json编码。

func Marshal(v interface{}) ([]byte, error)

//创建结构体
type Person struct {
	name    string
	address string
}


//序列化
per := Person{
	name:    "钢铁侠",
	address: "漫威",
}
perjson, err := json.Marshal(&per)
if err != nil {
	panic(err)
}
fmt.Printf("per序列化的json数据为为:%v", perjson)
fmt.Printf("per序列化的json字符串为:%v", string(perjson))

在这里插入图片描述
上面代码中序列化了一个Person对象,但打印时却打印失败,这是由于结构体成员都是小写的,只能在本包内访问,序列化没有意义,也不支持私有类的序列化。

type Person struct {
	Name    string
	Address string
}

将结构体改为公共类时就可以序列化了。
在这里插入图片描述

不同于Java一切皆对象的性质,Go中除了结构体还有map,数组,切片等。

//定义一个map类型
func initMap() map[string]string {
	var tmp map[string]string = map[string]string{}
	tmp["1"] = "aaa"
	tmp["2"] = "bbb"
	tmp["3"] = "ccc"
	return tmp
}

//对map序列化
a := initMap()

ajson, err := json.Marshal(&a)
if err != nil {
	panic("ajson序列化失败")
}
fmt.Printf("%v\n", ajson)
fmt.Println(string(ajson))


在这里插入图片描述

//输出序列化时的数据类型
fmt.Printf("%T\n", ajson)
fmt.Printf("%T\n", string(ajson))

在这里插入图片描述
可以看出序列化后时一个字节数组,通过string()函数将其转化为字符串,即为json字符串。

Go序列化时的tag标签的使用

在序列化时成员变量的名称均是首字母大写,然而在实际使用时需要统一书写规范,需要特定的名称,这就需要使用序列化时的tag标签。

{"Name":"钢铁侠","Address":"漫威"}

Go语言结构体序列化tag使用规则是在结构体字段后添加json:"name"并用反引号包裹。

type Person struct {
	Name    string `json:"person_name"`
	Address string `json:"person_address"`
	Age     int
}

在Name和Address使用了tag那么其序列化后的名称会变为自定义的person_name,Age成员没有使用tag因此不会改变。

per := Person{
	Name:    "钢铁侠",
	Address: "漫威",
	Age:     18,
}
perjson, err := json.Marshal(&per)
if err != nil {
	panic(err)
}
fmt.Printf("per序列化的json数据为为:%v", perjson)
fmt.Printf("per序列化的json字符串为:%v", string(perjson))

在这里插入图片描述
struct的tag只会在序列化时起作用不会影响结构体的使用。

反序列化

反序列化就是将序列化后的json字符串或者字节数组在转化为编程语言的内置数据结构。这个反序列化可以发生正在同一语言内,也可以发生在在不同语言中,例如,Java类序列化后网络传输到前端由json反序列化,或者其他任何后端语言将内置数据序列化后传输到前端。

在同一语言中对序列化的数据反序列化,Java实现方式与Go实现方式。

/**
go语言实现
*/

//定义结构体
type Person struct {
	Name    string `json:"person_name"`
	Address string `json:"person_address"`
	Age     int    `json:"person_age"`
}

//序列化
per := Person{
	Name:    "钢铁侠",
	Address: "漫威",
	Age:     18,
}
perjson, err := json.Marshal(&per)
if err != nil {
	panic(err)
}
fmt.Printf("per序列化的json数据为为:%v", perjson)
fmt.Printf("per序列化的json字符串为:%v", string(perjson))

在这里插入图片描述
序列化后为一个字节数组,可以通过string()方法转化为字符串。

func json.Unmarshal(data []byte, v any) error
该方法时反序列化方法,第一个参数为需要反序列化的字节数组,第二个参数为反序列化后数据的赋值变量。

//反序列化赋值变量
var per1 Person
err1 := json.Unmarshal(perjson, &per1)
if err1 != nil {
	panic(err1)
}
fmt.Printf("反序列化的数据per1%s,%s,%d", per1.Name, per1.Address, per1.Age)

在这里插入图片描述

str := `{"person_name":"钢铁侠","person_address":"漫威","person_age":18}`

var per2 Person
err2 := json.Unmarshal([]byte(str), &per2)
if err2 != nil {
	panic(err2)
}
fmt.Println(per2)

对字符串也可以反序列化,需要将字符串转化为字节数组,通过[]byte()方法。

单元测试

在Go语言的包中,需要测试某些方法是否正确,某些业务逻辑是否合理,需要通过测试,一般情况下需要在mian包中引入模块,再测试模块的方法或逻辑。这样的缺点是测试代码需要编写在主类中,然而在实际项目开发中,主类中有其自己的逻辑,将测试代码写在主类中,很繁琐,另外项目在运行时,无法在主类中修改测试d代码。而且在生产环境时还需要删除这些测试的代码。

为了解决这些问题Go语言提供了单元测试,可以针对包和模块的某些方法编程代码测试,而且这些测试模块是独立的,不用编写在主类中,不会影响主要的业务和代码。部署生产环境时直接删除测试模块的代码即可,非常方便。

Go语言中提供了testing单元测试框架,能够很好的解决这些问题。testing单元测试框架提供go test命令来实现单元测试和性能测试,基于这个框架针对相应的函数写测试用例。

testing 提供对 Go 包的自动化测试的支持。通过 go test 命令,能够自动执行如下形式的任何函数:

func TestXxx(*testing.T)

其中 Xxx 可以是任何字母数字字符串,用于识别测试用例。要编写一个新的测试套件,需要创建一个名称以 _test.go 结尾的文件,该文件包含 TestXxx 函数,如上所述。 将该文件放在与被测试的包相同的包中。该文件将被排除在正常的程序包之外,但在运行 “go test” 命令时将被包含。

testing单元测试的机制是编译器创建主类将将xxx_test.go包引入并调用TestXXX测试的方法,这些过程均有testing框架完成。

因此使用testing测试框架必须,按照其规范编写测试用例。

测试用例规范

  1. 测试的包必须使用_test.go后缀结尾;
  2. 测试包需要引入testing
  3. 测试方法必须以Test开头即TestXXX,且参数为测试包的的指针参数,一般为*testing.T

在这里插入图片描述

//mathutil.go

package mathutil

func add(x int, y int) int {
	return x + y
}

func sub(x int, y int) int {
	return (x - y)
}
//mathutil_test.go

package mathutil

import (
	"fmt"
	"testing"
)

func TestAdd(t *testing.T) {
	res := add(10, 13)
	if res != (10 + 13) {
		fmt.Println("add Fail,expect 23 but found", res)
	}
}

在这里插入图片描述

总结

  1. 测试用例文件名必须以_test.go结尾;
  2. 测试用例函数必须以Test开头;
  3. 测试函数的参数类型必须是*testing.T

在这里插入图片描述

  1. 运行测试用例的指令为go test无日志信息;go test -v打印详细信息
  2. 使用*testing.T的方法t.Fatalf打印错误退出程序和t.Logf方法可以打印日志。
  3. 测试用例独立于主程序,只在go test命令生效,PASS表示运行成功,FAIL表示运行失败。

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

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

相关文章

网络原理——IP地址与mac地址

目录 IP地址 IP地址 IP地址的组成 子网掩码 mac地址 冲突域与广播域 数据传输流程 IP地址 IP地址 互联网协议地址。每一个联网的主机都会分配一个IP地址。为32位二进制数&#xff0c;用4个.均分为四部分&#xff0c;在命令提示符中输入&#xff1a;ipconfig命令&#…

35岁的测试工程师被公司强行辞退,感叹道:我以前就该好好努力了

曾经的高薪软件测试工程师&#xff0c;今年35岁了&#xff0c;被公司劝退了&#xff0c;外卖跑到凌晨&#xff0c;很累&#xff0c;但还是有一种想诉说的冲动。哪怕让大家觉得已经说得太多了&#xff0c;烦了&#xff0c;都成祥林嫂了&#xff0c;但是&#xff0c;我是真的想说…

如何报名2023年CDGP数据治理专家认证?看这里

DAMA认证为数据管理专业人士提供职业目标晋升规划&#xff0c;彰显了职业发展里程碑及发展阶梯定义&#xff0c;帮助数据管理从业人士获得企业数字化转型战略下的必备职业能力&#xff0c;促进开展工作实践应用及实际问题解决&#xff0c;形成企业所需的新数字经济下的核心职业…

java中必会String的常用方法(IT枫斗者)

java中必会String的常用方法&#xff08;IT枫斗者&#xff09; 概述 在Java语言中&#xff0c;所有类似“ABC”的字面值&#xff0c;都是String类的实例&#xff1b;String类位于java.lang包下&#xff0c;是Java语言的核心类&#xff0c;提供了字符串的比较、查找、截取、大小…

NumPy 初学者指南中文第三版:6~10

原文&#xff1a;NumPy: Beginner’s Guide - Third Edition 协议&#xff1a;CC BY-NC-SA 4.0 译者&#xff1a;飞龙 六、深入探索 NumPy 模块 NumPy 具有许多从其前身 Numeric 继承的模块。 其中一些包具有 SciPy 对应版本&#xff0c;可能具有更完整的功能。 我们将在下一章…

教你用Python和wxPython模块打造一个ChatGPT式打字效果程序

应用场景&#xff0c;可以使用类似ChatGPT回复的打字效果来增强用户体验或提高应用程序的可读性&#xff1a; 聊天机器人&#xff1a;当聊天机器人回复用户消息时&#xff0c;使用打字效果可以更好地模拟真实聊天体验&#xff0c;增强用户对聊天机器人的信任感。电子邮件客户端…

尚硅谷大数据技术Hadoop教程-笔记04【Hadoop-MapReduce】

视频地址&#xff1a;尚硅谷大数据Hadoop教程&#xff08;Hadoop 3.x安装搭建到集群调优&#xff09; 尚硅谷大数据技术Hadoop教程-笔记01【大数据概论】尚硅谷大数据技术Hadoop教程-笔记02【Hadoop-入门】尚硅谷大数据技术Hadoop教程-笔记03【Hadoop-HDFS】尚硅谷大数据技术Ha…

DPU02国产USB转UART控制芯片替代CP2102

目录DPU02简介DPU02芯片特性应用DPU02简介 DPU02是高度集成的USB转UART的桥接控制芯片&#xff0c;该芯片为RS-232设计更新为USB设计&#xff0c;并简化PCB组件空间提供了一个简单的解决方案。       DPU02包括了一个USB 2.0全速功能控制器、USB收发器、振荡器、EEPROM和带…

HTML3.1表格

一、表格标签(行列的单元格方式整齐展示数据) 属性值&#xff1a; 标签名说明table 整体&#xff0c;包裹多个tr tr行&#xff0c;包裹tdtd单元格&#xff0c;包裹内容 注&#xff1a;标签嵌套关系&#xff1a;table>tr>td 代码&#xff1a; <!DOCTYPE html> &…

37岁测试工程师被裁,120天没找到工作,无奈...

从短期来看&#xff0c;程序员的确算是个不错的工作&#xff0c;薪水也比一般岗位高很多&#xff0c;但是从长远来看&#xff0c;程序员的中年危机会比其他岗位来的更早&#xff0c;很多程序员只有到了35岁左右&#xff0c;才能真正认清楚互联网行业&#xff0c;尤其是被裁之后…

日撸 Java 三百行day23-24

文章目录说明day23 使用具有通用性的队列1.复用技术2.包装类3.java内存分配4.代码day24 二叉树的建立1.思路2.代码说明 闵老师的文章链接&#xff1a; 日撸 Java 三百行&#xff08;总述&#xff09;_minfanphd的博客-CSDN博客 自己也把手敲的代码放在了github上维护&#xff…

看完这篇 教你玩转渗透测试靶机vulnhub——My File Server: 2

Vulnhub靶机My File Server: 2渗透测试详解Vulnhub靶机介绍&#xff1a;Vulnhub靶机下载&#xff1a;Vulnhub靶机安装&#xff1a;Vulnhub靶机漏洞详解&#xff1a;①&#xff1a;信息收集&#xff1a;②&#xff1a;FTP匿名登入③&#xff1a;SSH私钥登入④&#xff1a;SMB共享…

超详细从入门到精通,pytest自动化测试框架实战-测试运行钩子(七)

目录&#xff1a;导读前言一、Python编程入门到精通二、接口自动化项目实战三、Web自动化项目实战四、App自动化项目实战五、一线大厂简历六、测试开发DevOps体系七、常用自动化测试工具八、JMeter性能测试九、总结&#xff08;尾部小惊喜&#xff09;前言 pytest中用例执行相…

数据的表示和存储——

目录 浮点数的编码表示 浮点数类型 ​编辑 浮点数的表示 &#xff08;1&#xff09;浮点数&#xff08;Float Point&#xff09;的表示范围 &#xff08;2&#xff09;规格化数形式 &#xff08;3&#xff09;IEEE 754标准 其他形式的机器数表示 个人总结 浮点数的编码表…

深度学习_Learning Rate Scheduling

我们在训练模型时学习率的设置非常重要。 学习率的大小很重要。如果它太大&#xff0c;优化就会发散&#xff0c;如果它太小&#xff0c;训练时间太长&#xff0c;否则我们最终会得到次优的结果。其次&#xff0c;衰变率同样重要。如果学习率仍然很大&#xff0c;我们可能会简…

MySQL NDB Cluster使用docker compose一键部署

本文主要用来学习MySQL NDB Cluster 解决学习过程中的痛点&#xff1a;需要开启N台VMware虚拟机&#xff0c;电脑不堪重负 使用docker部署&#xff0c;完美解决 本文使用的docker image: mysql/mysql-cluster:8.0 创建mysql_cluster目录&#xff0c;后续操作都在这个目录下 …

基于html+css的盒子展示7

准备项目 项目开发工具 Visual Studio Code 1.44.2 版本: 1.44.2 提交: ff915844119ce9485abfe8aa9076ec76b5300ddd 日期: 2020-04-16T16:36:23.138Z Electron: 7.1.11 Chrome: 78.0.3904.130 Node.js: 12.8.1 V8: 7.8.279.23-electron.0 OS: Windows_NT x64 10.0.19044 项目…

系统集成项目管理工程师软考第三章习题(每天更新)

第一章指路&#xff1a;系统集成项目管理工程师软考第一章习题&#xff08;已完结&#xff09;_程序猿幼苗的博客-CSDN博客 第二章指路&#xff1a;系统集成项目管理工程师软考第二章习题&#xff08;已完结&#xff09;_程序猿幼苗的博客-CSDN博客 第3章信息系统集成专业技术…

基于密集学习的半监督目标检测

文章目录Dense Learning based Semi-Supervised Object Detection摘要本文方法实验结果Dense Learning based Semi-Supervised Object Detection 摘要 提出了一种基于密集学习(DSL)的无锚点的半监督目标检测算法用于分配多层级和精确的密集像素伪标签的自适应过滤器用于生成稳…

C++13:搜索二叉树

目录 搜索二叉树概念 模拟实现搜索二叉树 插入函数实现 插入函数实现&#xff08;递归&#xff09; 查找函数实现 删除函数实现 删除函数实现&#xff08;递归&#xff09; 中序遍历实现 拷贝构造函数实现 析构函数实现 赋值重载 我们在最开始学习二叉树的时候&#xff0c;…