Golang教程一(环境搭建,变量,数据类型,数组切片map)

目录

一、环境搭建

1.windows安装

2.linux安装 

3.开发工具

二、变量定义与输入输出

1.变量定义

2.全局变量与局部变量

3.定义多个变量

4.常量定义

5.命名规范

6.输出

7.输入 

三、基本数据类型

1.整数型

2.浮点型

3.字符型

4.字符串类型

转义字符

多行字符串

5.布尔类型

四、数组、切片、map

1.数组

 2.切片

make函数

切片面试题 

3.Map

map面试题 


一、环境搭建

官网

https://go.dev/dl/

访问不了的就访问中文网就好了

go安装包下载

https://studygolang.com/dl

安装指定版本的安装包就好了

1.windows安装

选择 xxx.windows-amd64.msi

  • 将go的对应bin目录设置为环境变量,这一步是方便可以在命令行里面直接使用go命令
  • 将go的第三方bin目录设置为环境变量,一般是在用户目录下,这一步是为了以后使用go install安装的第三方可执行文件可以直接使用

2.linux安装 

选择 xxx.linux-amd64.tar.gz

该站点比较快:All releases - The Go Programming Language

# 下载

wget https://golang.google.cn/dl/go1.22.2.linux-amd64.tar.gz

# 解压

tar -xvf go1.22.2.linux-arm64.tar.gz -C /usr/local

# 配置环境变量

echo 'export GO111MODULE=on' >> /etc/profile
echo 'export GOROOT=/usr/local/go' >> /etc/profile
echo 'export GOPATH=/home/gopath' >> /etc/profile
echo 'export PATH=$PATH:$GOROOT/bin:$GOPATH/bin' >> /etc/profile

source /etc/profile

# 创建go包安装目录

mkdir -p /home/gopath

# 设置代理

go env -w GOPROXY=https://goproxy.cn,direct

# 检查成功

go version

3.开发工具

推荐goland

二、变量定义与输入输出

1.变量定义

package mainimport "fmt"func main() {// 先定义,再赋值var name stringname = "os_lee1"fmt.Println(name)// 定义加赋值var userName string = "os_lee1"fmt.Println(userName)
}

如果一个变量定义了,但是没有赋值,那么这个变量的值就是这个类型的 "零值" 

// 变量类型省略
var name = "os_lee"// 简单声明
name := "os_lee"

2.全局变量与局部变量

定义在函数体(包括main函数)内的变量都是局部变量,定义了就必须使用
定义在外部的变量就是全局变量,可以只定义不使用 

package mainimport "fmt"// 全局变量可以不使用
var userName = "oslee_全局" func main() {// 局部变量var name = "oslee_局部"// 在函数体内定义的变量,必须要使用fmt.Println(name)
}

3.定义多个变量

package mainimport "fmt"func main() {var name1, name2, name3 string // 定义多个变量var a1, a2 = "os", "lee" // 定义多个变量并赋值a3, a4 := "os", "lee" // 简短定义多个变量并赋值fmt.Printf("name1: %s, name2: %s, name3: %s\n", name1, name2, name3)fmt.Printf("a1: %s, a2: %s, a3: %s, a4: %s\n", a1, a2, a3, a4)
}
package mainimport "fmt"var (name     string = "os"userName        = "os_lee"
)func main() {fmt.Println(name, userName)
}

4.常量定义

定义的时候就要赋值
赋值之后就不能再修改了

package mainimport "fmt"const name string = "os_lee" // 定义就要赋值func main() {fmt.Println(name)
}

5.命名规范

核心思想:首字母大写的变量、函数。方法,属性可在包外进行访问

6.输出

package mainimport "fmt"func main() {fmt.Println("os_lee")fmt.Println(1)fmt.Println(true)fmt.Println("什么", "都", "可以", "输出")
}

格式化输出

package mainimport "fmt"func main() {fmt.Printf("%v\n", "你好")           // 可以作为任何值的占位符输出fmt.Printf("%v %T\n", "os", "lee") // 打印类型fmt.Printf("%d\n", 3)              // 整数fmt.Printf("%.2f\n", 1.25)         // 小数fmt.Printf("%s\n", "哈哈哈")          // 字符串fmt.Printf("%#v\n", "")            // 用go的语法格式输出,很适合打印空字符串// 还有一个用的比较多的就是将格式化之后的内容赋值给一个变量name := fmt.Sprintf("%v", "你好")fmt.Println(name)
}

7.输入 

package mainimport "fmt"func main() {fmt.Println("输入您的名字:")var name stringfmt.Scan(&name) // 这里记住,要在变量的前面加个&, 后面讲指针会提到fmt.Println("你输入的名字是", name)
}

三、基本数据类型

go语言的基本数据类型有

  1. 整数形
  2. 浮点型
  3. 复数
  4. 布尔
  5. 字符串

1.整数型

go语言的整数类型,具体细分有很多

var n1 uint8 = 2 
var n2 uint16 = 2 
var n3 uint32 = 2 
var n4 uint64 = 2 
var n5 uint = 2 
var n6 int8 = 2 
var n7 int16 = 2 
var n8 int32 = 2 
var n9 int64 = 2 
var n10 int = 2 

大家只需要记住以下几点

  1. 默认的数字定义类型是int类型
  2. 带个u就是无符号,只能存正整数
  3. 后面的数字就是2进制的位数
  4. uint8还有一个别名 byte, 一个字节=8个bit位
  5. int类型的大小取决于所使用的平台

例如uint8,那就是8个二进制位,都用来存储数据,那最小就是0,最大就是2的八次方-1=255

那int8,因为要拿一位存符合,使用实际只有七位可用,所以最小的就是负2的七次方=-128,最大的就是2的七次方-1=127

至于为什么要减一,其实很好理解,因为实际到最后一个数字的时候,已经向前进位了,例如一个小时是60分钟,但是分钟最大只有59

第五点的测试

我是64位操作系统,那么我会试一下int是不是就是int64的最大上限

2的63次方-1=9223372036854775807fmt.Printf("%.0f\n", math.Pow(2, 63))
var n1 int = 9223372036854775807
fmt.Println(n1)
var n2 int = 9223372036854775808 // 看它报不报错
fmt.Println(n2)

2.浮点型

Go语言支持两种浮点型数:float32 和 float64

  • float32 的浮点数的最大范围约为3.4e38,可以使用常量定义:math.MaxFloat32
  • float64 的浮点数的最大范围约为 1.8e308,可以使用一个常量定义:math.MaxFloat64

如果没有显式声明,则默认是float64

3.字符型

注意哦,是字符,不是字符串

比较重要的两个类型是byte(单字节字符)和rune(多字节字符)

package mainimport "fmt"func main() {var c1 = 'a'var c2 = 97fmt.Println(c1) // 直接打印都是数字fmt.Println(c2)fmt.Printf("%c %c\n", c1, c2) // 以字符的格式打印var r1 rune = '中'fmt.Printf("%c\n", r1)
}

在 Go 中,字符的本质是一个整数,直接输出时,是该字符对应的 UTF-8 编码的码值
可以直接给某个变量赋一个数字,然后按格式化输出时 %c ,会输出该数字对应的 unicode 字符
字符类型是可以进行运算的,相当于一个整数,因为它都对应有 Unicode 码。

4.字符串类型

和字符不一样的是,字符的赋值是单引号,字符串的赋值是双引号 

var s string = "lee李"
fmt.Println(s)

转义字符

一些常用的转义字符

fmt.Println("枫枫\t知道")              // 制表符
fmt.Println("枫枫\n知道")              // 回车
fmt.Println("\"枫枫\"知道")            // 双引号
fmt.Println("枫枫\r知道")              // 回到行首
fmt.Println("C:\\pprof\\main.exe") // 反斜杠

多行字符串

在``这个里面,再出现转义字符就会原样输出了

package mainimport "fmt"func main() {str := `今天
天气
真好
`fmt.Println(str)
}

5.布尔类型

  • 布尔型数据只有 true(真)和 false(假)两个值
  • 布尔类型变量的默认值为false
  • Go 语言中不允许将整型强制转换为布尔型
  • 布尔型无法参与数值运算,也无法与其他类型进行转换
  • 零值问题
    如果我们给一个基本数据类型只声明不赋值,那么这个变量的值就是对应类型的零值,例如int就是0,bool就是false,字符串就是""

package mainimport "fmt"func main() {var a1 intvar a2 float32var a3 stringvar a4 boolfmt.Printf("%#v\n", a1)fmt.Printf("%#v\n", a2)fmt.Printf("%#v\n", a3)fmt.Printf("%#v\n", a4)
}

四、数组、切片、map

1.数组

数组(Array)是一种非常常见的数据类型,几乎所有的计算机编程语言中都会用到它

  1. 数组里的元素必须全部为同一类型,要嘛全部是字符串,要嘛全部是整数
  2. 声明数组时,必须指定其长度或者大小
package mainimport "fmt"func main() {var array [3]int = [3]int{1, 2, 3}fmt.Println(array)var array1 = [3]int{1, 2, 3}fmt.Println(array1)var array2 = [...]int{1, 2, 3}fmt.Println(array2)
}

 如果要修改某个值,只能根据索引去找然后替换

var array1 = [3]int{1, 2, 3}
array1[0] = 10 // 根据索引找到对应的元素位置,然后替换
fmt.Println(array1)

 2.切片

很明显啊,go里面的数组,长度被限制死了,所以不经常用

所以go出了一个数组plus,叫做slice(切片)

切片(Slice)相较于数组更灵活,因为在声明切片后其长度是可变的

package mainimport "fmt"func main() {// 定义一个字符串切片var list []stringlist = append(list, "枫枫")list = append(list, "知道")fmt.Println(list)fmt.Println(len(list)) // 切片长度// 修改第二个元素list[1] = "不知道"fmt.Println(list)
}

make函数

除了基本数据类型,其他数据类型如果只定义不赋值,那么实际的值就是nil

// 定义一个字符串切片
var list []string
fmt.Println(list == nil) // true

那么我们可以通过make函数创建指定长度,指定容量的切片了

make([]type, length, capacity)
package mainimport "fmt"func main() {// 定义一个字符串切片var list = make([]string, 0)fmt.Println(list, len(list), cap(list))fmt.Println(list == nil) // falselist1 := make([]int, 2, 2)fmt.Println(list1, len(list1), cap(list1))
}

为什么叫切片?
因为切片是数组切出来的

package mainimport "fmt"func main() {var list = [...]string{"a", "b", "c"}slices := list[:] // 左一刀,右一刀 变成了切片fmt.Println(slices)fmt.Println(list[1:2]) // b
}

切片排序

package mainimport ("fmt""sort"
)func main() {var list = []int{4, 5, 3, 2, 7}fmt.Println("排序前:", list)sort.Ints(list)fmt.Println("升序:", list)sort.Sort(sort.Reverse(sort.IntSlice(list)))fmt.Println("降序:", list)
}

切片面试题 

面试题1:什么是Go语言中的切片?

答案: Go语言中的切片(slices)是一种灵活的、动态大小的、基于数组的抽象数据类型。它并不存储任何数据,而是指向底层数组的一个片段,包含了三个信息:指向数组的指针、长度(len)和容量(cap)。长度表示切片当前拥有的元素个数,容量则是切片可以扩展到的最大元素个数,容量等于或大于长度。

面试题2:切片的扩容是如何工作的?

答案: 当向切片添加元素超出其当前容量时,Go语言会自动扩容切片。扩容的具体策略并不是固定的,但大致遵循以下规则:

  • 如果切片的容量不足以容纳新增元素,Go 会创建一个新的更大的底层数组,将原有数据复制到新数组,并更新切片的指针和容量。
  • 扩容因子通常为原来容量的2倍,但是也可能会根据实际情况调整,比如在Go 1.17版本之后,根据内存分配器的行为,扩容可能会跳跃式增长以更好地适应内存分配器的粒度。
  • 新容量至少会增加到原来的两倍+所需添加的元素数量,以尽量减少频繁的扩容操作。

面试题3:切片与数组有什么区别?

答案

  1. 长度可变性

    • 数组(array)的长度在声明时确定并且不能改变。
    • 切片(slice)虽然在声明时可以指定初始长度,但可以在运行时动态改变其长度(增删元素),不过容量有限制。
  2. 存储结构

    • 数组是一个定长的、连续的内存区域。
    • 切片不是数据结构,它只是一个描述符,指向一个数组的一部分。
  3. 引用行为

    • 数组变量直接存储数据,赋值操作会复制整个数组的内容。
    • 切片变量存储的是指向数组的指针和长度、容量信息,赋值操作只会复制切片描述符,不会复制底层数据。

面试题4:浅拷贝和深拷贝

浅拷贝(Shallow Copy): 浅拷贝是创建一个新的切片,但它仍然指向同一个底层数组。这意味着对新切片所做的修改会影响到原始切片所指向的数据。

// 示例1:直接赋值
original := []int{1, 2, 3}
copied := original // 此时copied是对original的浅拷贝

// 示例2:使用内置的copy函数
original := []int{1, 2, 3}
copied := make([]int, len(original))
copy(copied, original) // 这也是浅拷贝,copied和original共享相同的底层数组

深拷贝(Deep Copy): 深拷贝是创建一个与原始切片完全独立的新切片,包含一个全新的底层数组。对新切片所做的修改不会影响到原始切片。

// 手动循环遍历复制每一个元素
original := []int{1, 2, 3}
copied := make([]int, len(original))
for i, v := range original {
copied[i] = v
}// 或者使用反射(reflect)包,但请注意这不是最优实践,仅作演示
import "reflect"
original := []int{1, 2, 3}
copied := reflect.ValueOf(original).Clone().Interface().([]int)

3.Map

  1. Go语言中的map(映射、字典)是一种内置的数据结构,它是一个无序的key-value对的集合
  2. map的key必须是基本数据类型,value可以是任意类型
  3. 注意,map使用之前一定要初始化
package mainimport "fmt"func main() {// 声明var m1 map[string]string// 初始化1m1 = make(map[string]string)// 初始化2m1 = map[string]string{}// 设置值m1["name"] = "枫枫"fmt.Println(m1)// 取值fmt.Println(m1["name"])// 删除值delete(m1, "name")fmt.Println(m1)// 声明并赋值var m2 = map[string]string{}fmt.Println(m2)var m3 = make(map[string]string)fmt.Println(m3)}

map取值

  1. 如果只有一个参数接,那这个参数就是值,如果没有,这个值就是类型的零值
  2. 如果两个参数接,那第二个参数就是布尔值,表示是否有这个元素
package mainimport "fmt"func main() {// 声明并赋值var m1 = map[string]int{"age": 21,}age1 := m1["age1"] // 取一个不存在的fmt.Println(age1)age2, ok := m1["age1"]fmt.Println(age2, ok)
}

map面试题 

面试题1:什么是Go语言中的map?

答案: Go语言中的map是一种关联数组或字典类型的数据结构,它存储键值对(key-value pairs),通过键(key)快速查找对应的值(value)。键和值可以是任何类型,但键的类型必须支持相等比较,通常为整型、浮点型、字符串或复合类型(如结构体,但结构体内的字段必须支持相等比较)。

面试题2:Go语言中的map何时会引发panic?

答案

  • 在使用尚未初始化的map时(即nil map)执行读写操作,会导致panic。
  • 在迭代map的过程中,如果同时修改该map,也会导致panic,除非使用for range循环迭代并在循环体内使用delete函数删除元素。

面试题3:Go语言中map的扩容是如何进行的?

Go语言中的map在底层实现上使用了哈希表。当map中的元素数量越来越多,达到一定的负载因子时,Go语言会自动触发map的扩容操作。扩容是为了保持map操作的高效性,防止哈希冲突过于密集,导致性能下降。

扩容的具体流程如下:

  1. 负载因子判断: 当map的元素数量(entry count)与其桶(bucket)数量的比例超过一定阈值时(通常大约是6.5),map会触发扩容。这个阈值可以通过runtime包的内部常量mapExpandHeapSizemapExpandLoadFactor间接推算出来。

  2. 新桶分配: 扩容时,Go会创建一个新的、大小翻倍的哈希表。例如,如果原map的桶数量是2^N,则新表的桶数量将是2^(N+1)。

  3. 元素迁移: Go采用了渐进式(incremental)的迁移策略,不会一次性将所有元素从旧表迁移到新表。在每次map的读写操作时,如果发现正在进行扩容操作,就会顺带将旧表中的部分元素迁移到新表中。每次操作最多迁移两个桶(bucket)的数据。

  4. 保持引用关系: 在扩容过程中,map的旧表和新表会同时存在,直到所有元素都迁移到新表为止。旧表的最后一个桶会存储一个指向新表的指针,以确保在扩容过程中依然能正确找到已迁移的元素。

  5. 空间回收: 所有元素都迁移到新表后,旧表的空间最终会被垃圾回收机制释放。

值得注意的是,上述细节基于Go语言的早期版本,Go语言的map扩容机制在不同版本间可能会有所调整。最新的Go版本可能会根据具体情况采用不同的扩容策略和负载因子阈值。

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

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

相关文章

深度学习简介

深度学习简介 一、引言:深度学习的兴起 简短介绍深度学习的历史背景 深度学习,作为人工智能领域的一颗冉冉升起的新星,其根源可以追溯到上世纪的感知机学习算法。这种算法模拟人类的神经元行为,是最早期的尝试之一。然而&#x…

OpenLayers6实战,OpenLayers实现鼠标拖拽方式绘制矩形(拖拽方式绘制长方形和正方形)

专栏目录: OpenLayers实战进阶专栏目录 前言 本章介绍使用OpenLayers在地图上实现鼠标拖拽方式绘制矩形(拖拽方式长方形和正方形)。 OpenLayers本身是可以通过鼠标点击多个点的方式来绘制多边形的,当然也包括长方形和正方形,但是这种多边形绘制出来的图形并不是准确的“…

每天学点儿Python(6) -- 列表和枚举

列表是Python中内置的可变序列,类使用C/C中的数组,使用 [ ] 定义列表,列表中的元素与元素之间用英文逗号( , )分隔, 但是Python中列表可以存储任意类型的数据,且可以混存(即类型可以…

Partisia Blockchain 何以落地隐私技术的高能场景应用?

致力于隐私保护、互操作性和可持续创新的 Layer1 区块链新星,Partisia Blockchain 以安全公平标榜,带给加密用户无忧交易的体验环境。对于这样一个融合零知识证明(ZK)技术和多方计算(MPC)的全新项目来说&am…

18_SPI通信外设

SPI通信外设 SPI通信外设SPI外设简介SPI框图SPI基本结构主模式全双工连续传输非连续传输 SPI通信外设 SPI外设简介 STM32内部集成了硬件SPI收发电路,可以由硬件自动执行时钟生成、数据收发等功能,减轻CPU的负担 可配置8位/16位数据帧、高位先行/低位先…

wsl 2在windows11上的设置

详细参考:Manual installation steps for older versions of WSL | Microsoft Learn 1.系统组件要打开 分别是:Hyper-V、虚拟机平台、适用于Windows的Linux子系统 2.以管理员方式运行命令行,逐步执行下面的命令 update to WSL 2, you must…

opc ua 环境构建(记录一)

1、准备 Siemens Simatic WinCC v7.5 二、配置 SIMATIC NET与S7-200 SMART 集成以太网口OPC 通信(TIA平台) 硬件: ①S7-200 SMART ②PC 机 ( 集成以太网卡) 软件: ① STEP 7-Micro/WIN SMART V2.1 ② STEP 7 Professional(TIA Portal V13 SP1 Upd 9) ③ SIMATIC NET …

在直播间卖云,云厂商终于“疯了”

图片|电影《疯狂的石头》截图 ©自象限原创 作者丨程心 云厂商们,在直播间打起来了! 继阿里云在罗永浩直播间亮相、京东云硬刚友商之后,腾讯云也开始在“直播间”送起了福利。 4月8日,腾讯云发布新一代AIGC存…

记录vite打包并上传到npm

开始 起因:我们单位这个项目用的vitereact使用print打印 开发环境没问题、一到打包时就卡住、所以我就想单独打包成组件在引用看看还有问题么、结果还真可以!又是离谱的一天 首先需要把npm的分支切换成官网地址、因为只有官网地址才能登陆npm账号 这里说…

FreeRTOS学习 -- 移植

一、添加FreeRTOS源码 在基础工程中新建一个名为FreeRTOS的文件夹,创建FreeRTOS文件夹以后将FreeRTOS的源码添加到这个文件夹中。 portable 文件夹,只需要保留keil、MemMang 和 RVDS这三个文件夹,其他的都可以删除掉。 移植FreeRTOSConfig…

SimOne协作版正式发布!“云+端”一体化,加速自动驾驶技术迭代!

创新的“云端”一体化方案 让11大于2 两端登录 场景共享 本地算法 云端并发 颠覆传统自动驾驶研发工作方式 加速自动驾驶算法迭代与优化 SimOne协作版正式发布! 什么是SimOne协作版? SimOne协作版,一个创新的“云端”一体化产品。 它将…

【数学建模】机器人避障问题

已知: 正方形5的左下顶点坐标 ( 80 , 60 ) (80,60) (80,60),边长 150 150 150机器人与障碍物的距离至少超过 10 10 10个单位规定机器人的行走路径由直线段和圆弧组成,其中圆弧是机器人转弯路径。机器人不能折线转弯,转弯路径由与…

代码随想录-算法训练营day02【数组02:滑动窗口、螺旋矩阵】

代码随想录-035期-算法训练营【博客笔记汇总表】-CSDN博客 https://docs.qq.com/doc/DUGRwWXNOVEpyaVpG?uc71ed002e4554fee8c262b2a4a4935d8977.有序数组的平方 ,209.长度最小的子数组 ,59.螺旋矩阵II ,总结 建议大家先独立做题,…

基于 MATLAB 和 App Designer 的 UI 交互框架开发的一款电力系统潮流计算工具

基于 MATLAB 和 App Designer 的 UI 交互框架开发的一款电力系统潮流计算工具 文章目录 基于 MATLAB 和 App Designer 的 UI 交互框架开发的一款电力系统潮流计算工具一、软件介绍二、软件功能1、数据输入 2、潮流作业设置3、 潮流结果报表及可视化三、 软件设计思路1 、牛顿拉…

【Vue3语法单文件——自用】

1. Vue3基础语法 <script setup> import { ref,computed } from vue// 定义响应式的变量 const count ref(0) const author ref({name: John Doe,books: [Vue 2 - Advanced Guide,Vue 3 - Basic Guide,Vue 4 - The Mystery] }) //定义props const props defineProps(…

[RK3399 Linux] 移植Linux 5.2.8内核详解

背景是在RK3399上面移植Rockchip官方提供的u-boot 2017.09 一、linux内核 1.1 源码下载 内核源码下载地址为:《https://www.kernel.org/》: 也可以到内核镜像网址下载https://mirrors.edge.kernel.org/pub/linux/kernel/,这里下载速度更快。 如果下载速度太慢,无法下载,…

蓝牙app设计(方案二) E4A (时钟 优缺点)

例程改的! 主界面 虽然上面有搜索功能,但是本人建议先自行配对在使用,这样更好用,把要使用的设备收藏一下更好找哦(这样就是橙色的了,只需要点对应蓝牙左边) 代码修改部分 原版是不停向下滚动显示,这样个人觉得不太好看,所以加了个时钟,到对应时钟周期清空(达到刷…

BGP小实验

光只是知道理论还不行&#xff0c;还是要多动手练练&#xff0c;就练一个bgp实验吧&#xff0c;梳理一下做题思路 实验要求&#xff1a; 大体要求就是&#xff1a;R1的环回可以ping通R2-R5的环回&#xff0c;R5同理 思路&#xff1a; 基础配置&#xff1a; 第一步先把地址环…

二叉树练习day.7

530.二叉搜索树的最小绝对差 链接&#xff1a;. - 力扣&#xff08;LeetCode&#xff09; 题目描述&#xff1a; 给你一个二叉搜索树的根节点 root &#xff0c;返回 树中任意两不同节点值之间的最小差值 。 差值是一个正数&#xff0c;其数值等于两值之差的绝对值。 示例 1&…

【记录】Prompt模板|作为甲方怎么清晰专业地描述自己的需求(又名“乙方,给你的甲方扔个GPT解放自己吧”)

这篇Prompt摘抄并修改自朋友送给我的书的第49页5.2.3让ChatGPT构建提示&#xff0c;质量挺不错&#xff0c;支持一下她的博客&#xff1a;【好书推荐2】AI提示工程实战&#xff1a;从零开始利用提示工程学习应用大语言模型。 书长这样&#xff1a; 不啰嗦了&#xff0c;正文如…