当前位置: 首页 > article >正文

Go 语言语法精讲:从 Java 开发者的视角全面掌握

《Go 语言语法精讲:从 Java 开发者的视角全面掌握》

    • 一、引言
      • 1.1 为什么选择 Go?
      • 1.2 适合 Java 开发者的原因
      • 1.3 本文目标
    • 二、Go 语言环境搭建
      • 2.1 安装 Go
      • 2.2 推荐 IDE
      • 2.3 第一个 Go 程序
    • 三、Go 语言基础语法
      • 3.1 变量与常量
        • 3.1.1 声明变量
        • 3.1.2 常量定义
      • 3.2 数据类型
        • 3.2.1 基本类型
        • 3.2.2 复合类型
      • 3.3 运算符
    • 四、流程控制
      • 4.1 条件语句
      • 4.2 循环语句
        • 4.2.1 遍历数组、切片、映射
      • 4.3 分支语句
    • 五、函数与方法
      • 5.1 函数定义
        • 5.1.1 错误处理
      • 5.2 方法
    • 六、错误处理
      • 6.1 `error` 接口
      • 6.2 `defer` 语句
      • 6.3 `panic` 和 `recover`
    • 七、并发编程
      • 7.1 Goroutine
      • 7.2 Channel
      • 7.3 `select`
    • 八、结构体与接口
      • 8.1 结构体
      • 8.2 接口
    • 九、高级特性
      • 9.1 指针
      • 9.2 反射
      • 9.3 闭包
    • 十、代码组织与包管理
      • 10.1 包的定义与导入
      • 10.2 依赖管理
    • 十一、常见陷阱与最佳实践
      • 11.1 零值初始化
      • 11.2 切片的底层机制
      • 11.3 并发安全
    • 十二、总结与展望
    • 附录
      • 12.1 Go 语言标准库速查表
      • 12.2 示例代码
        • HTTP 服务器
        • 并发计数器

一、引言

大家好!今天咱们来聊聊 Go 语言,一个让 Java 开发者又爱又恨的编程语言。为啥说又爱又恨呢?爱它是因为简单高效,恨它是因为有些地方和 Java 完全不一样,刚上手可能会有点懵。不过别担心,我就是来帮大家捋顺这些坑的!

1.1 为什么选择 Go?

  • 简单高效:Go 的语法简洁,写起来像搭积木,运行起来又快又稳。
  • 并发支持:Goroutine 和 Channel 是 Go 的杀手锏,写并发程序就像喝奶茶一样轻松。
  • 跨平台:写一次代码,到处跑,Windows、Linux、Mac 都能搞定。

1.2 适合 Java 开发者的原因

  • Java 开发者对面向对象、类型系统已经很熟悉了,Go 的学习曲线会平缓很多。
  • Go 的并发模型和 Java 的线程模型完全不同,正好是个拓宽视野的好机会!

1.3 本文目标

这篇文章的目标就是帮大家快速掌握 Go 的语法,少踩坑,多涨经验!如果觉得有用,记得点个赞、收藏一下,关注我,后续还会带来更多 Go 实战内容哦!

二、Go 语言环境搭建

2.1 安装 Go

第一步就是把 Go 安装好。去官网 golang.org/dl 下载最新版本,Windows、Mac、Linux 都有支持。安装完后,记得配置环境变量:

  • GOROOT:Go 的安装路径,比如 C:\Go
  • GOPATH:你的工作区路径,比如 D:\go_workspace
  • GOBIN:可执行文件路径,一般设置为 $GOROOT/bin

2.2 推荐 IDE

我强烈推荐用 VS Code + Go 扩展!安装 VS Code 后,打开扩展市场,搜 Go 插件装上就行。调试工具用 delve,简单又强大。

2.3 第一个 Go 程序

写个 hello.go 玩玩:

package mainimport "fmt"func main() {fmt.Println("Hello, Go 开发者!")
}

运行命令:

go run hello.go

输出:

Hello, Go 开发者!

是不是超简单?Java 开发者看到这行代码可能会觉得有点陌生,但别急,后面会慢慢熟悉!

三、Go 语言基础语法

3.1 变量与常量

3.1.1 声明变量

Go 里声明变量有两种方式:

var name string = "张三"  // 显式声明
age := 25                 // 类型推导

Java 开发者可能会觉得 := 很奇怪,其实它就是 Go 的“自动类型推导”,和 Java 的 var 类似,但更灵活!

3.1.2 常量定义
const PI float64 = 3.14159

常量一旦定义就不能改了,Java 里用 final 修饰的变量就是这个意思。

3.2 数据类型

3.2.1 基本类型

Go 的基本类型和 Java 差不多,但有个大不同:没有包装类型!比如 Java 里有 Integer,Go 里直接用 int,简单粗暴!

var a bool = true
var b int = 42
var c float64 = 3.14
var d string = "Hello, Go!"
3.2.2 复合类型
  • 数组:长度固定,比如 var arr [5]int
  • 切片:动态数组,用 make 创建:slice := make([]int, 5)
  • 结构体:自定义数据类型,类似 Java 的类:
type Person struct {Name stringAge  int
}p := Person{Name: "张三", Age: 25}
  • 映射(map):键值对,用法和 Java 的 HashMap 类似:
m := make(map[string]int)
m["key1"] = 42

3.3 运算符

Go 的运算符和 Java 差不多,但有个坑:没有三元运算符的简化形式!比如 Java 里 a ? b : c,Go 里得老老实实写 if-else

result := 0
if a > b {result = a
} else {result = b
}

四、流程控制

4.1 条件语句

Go 的 if 语句可以内联变量声明,这个 Java 里没有!

if n := 42; n%2 == 0 {fmt.Println("偶数")
} else {fmt.Println("奇数")
}

4.2 循环语句

Go 只有一种循环:for!但别小看它,功能很强大:

// 传统 for 循环
for i := 0; i < 5; i++ {fmt.Println(i)
}// while 替代形式
for i := 0; i < 5 {i++
}// 无限循环
for {fmt.Println("无限循环中...")
}
4.2.1 遍历数组、切片、映射

range 关键字:

// 遍历数组
arr := [3]int{1, 2, 3}
for index, value := range arr {fmt.Printf("索引: %d, 值: %d\n", index, value)
}// 遍历切片
slice := []string{"苹果", "香蕉", "橙子"}
for _, fruit := range slice {fmt.Println(fruit)
}// 遍历映射
m := map[string]int{"a": 1, "b": 2}
for key, value := range m {fmt.Printf("键: %s, 值: %d\n", key, value)
}

4.3 分支语句

Go 的 switch 默认不需要 break,写起来更简洁:

day := "Monday"
switch day {
case "Monday":fmt.Println("周一,打工人")
case "Tuesday":fmt.Println("周二,继续肝")
default:fmt.Println("周末快乐!")
}

五、函数与方法

5.1 函数定义

Go 的函数可以有多个返回值,这个 Java 里做不到!

func add(a, b int) (int, int) {return a + b, a - b
}sum, diff := add(10, 5) // sum=15, diff=5
5.1.1 错误处理

Go 没有 try-catch,而是通过返回 error 来处理错误:

func divide(a, b float64) (float64, error) {if b == 0 {return 0, errors.New("除数不能为零")}return a / b, nil
}result, err := divide(10, 0)
if err != nil {fmt.Println("错误:", err)
} else {fmt.Println("结果:", result)
}

5.2 方法

方法是绑定到结构体上的函数,用 receiver 表示:

type Calculator struct {Result int
}// 值接收者
func (c Calculator) Add(a int) int {return c.Result + a
}// 指针接收者
func (c *Calculator) Subtract(a int) {c.Result -= a
}calc := Calculator{Result: 10}
sum := calc.Add(5)       // sum=15
calc.Subtract(3)         // calc.Result=7

六、错误处理

6.1 error 接口

Go 的错误处理很简单:返回 error,然后检查 err != nil

func readFile(filename string) ([]byte, error) {file, err := os.Open(filename)if err != nil {return nil, err}defer file.Close() // 确保文件关闭return ioutil.ReadAll(file)
}data, err := readFile("test.txt")
if err != nil {fmt.Println("读取文件失败:", err)return
}
fmt.Println("文件内容:", string(data))

6.2 defer 语句

defer 是 Go 的“延迟执行”,常用来释放资源:

func openResource() {resource := acquireResource()defer releaseResource(resource) // 确保资源被释放// 使用 resource
}

6.3 panicrecover

panic 用于抛出异常,recover 用于捕获异常:

func main() {defer func() {if r := recover(); r != nil {fmt.Println("捕获到异常:", r)}}()riskyOperation()
}func riskyOperation() {panic("出错了!")
}

七、并发编程

7.1 Goroutine

Goroutine 是 Go 的并发单元,启动方式超简单:

func sayHello() {fmt.Println("Hello from Goroutine!")
}func main() {go sayHello() // 启动 Goroutinetime.Sleep(time.Second) // 等待 Goroutine 执行
}

7.2 Channel

Channel 是 Goroutine 之间的通信工具:

func main() {ch := make(chan int) // 创建通道go func() {ch <- 42 // 发送数据}()result := <-ch // 接收数据fmt.Println("结果:", result)
}

7.3 select

select 用于监听多个 Channel 的事件:

func main() {ch1 := make(chan string)ch2 := make(chan string)go func() {time.Sleep(2 * time.Second)ch1 <- "通道1"}()go func() {time.Sleep(1 * time.Second)ch2 <- "通道2"}()select {case msg1 := <-ch1:fmt.Println(msg1)case msg2 := <-ch2:fmt.Println(msg2)}
}

八、结构体与接口

8.1 结构体

结构体是自定义数据类型,可以嵌入匿名字段:

type Address struct {City  stringState string
}type Person struct {Name    stringAge     intAddress // 嵌入匿名字段
}p := Person{Name: "张三",Age:  25,Address: Address{City:  "北京",State: "中国",},
}fmt.Println(p.City) // 输出: 北京

8.2 接口

Go 的接口是隐式实现的,不需要显式声明:

type Speaker interface {Speak() string
}type Dog struct{}func (d Dog) Speak() string {return "汪汪"
}func main() {var s Speaker = Dog{}fmt.Println(s.Speak()) // 输出: 汪汪
}

九、高级特性

9.1 指针

指针是 Go 的核心特性之一,用来直接操作内存地址:

func main() {a := 42ptr := &a // 获取 a 的地址fmt.Println(*ptr) // 解引用,输出 42
}

9.2 反射

反射可以动态操作变量的类型和值:

func main() {var x float64 = 3.4v := reflect.ValueOf(x)t := reflect.TypeOf(x)fmt.Println("类型:", t) // 输出: float64fmt.Println("值:", v)   // 输出: 3.4
}

9.3 闭包

闭包可以捕获外部变量:

func main() {adder := func(a int) int {return a + 10}fmt.Println(adder(5)) // 输出: 15
}

十、代码组织与包管理

10.1 包的定义与导入

每个 Go 文件都属于一个包:

package mainimport ("fmt""math"
)func main() {fmt.Println(math.Sqrt(16)) // 输出: 4
}

10.2 依赖管理

go mod 管理依赖:

go mod init myproject
go mod tidy

十一、常见陷阱与最佳实践

11.1 零值初始化

Go 的变量默认值是“零值”,比如 int0boolfalsenil 是空值。

11.2 切片的底层机制

切片有三个部分:长度、容量和底层数组。扩容时会创建新数组,可能导致性能问题:

func main() {slice := make([]int, 0, 5) // 长度0,容量5slice = append(slice, 1, 2, 3, 4, 5, 6) // 扩容fmt.Println(slice)
}

11.3 并发安全

并发时要注意数据竞争,可以用 sync.Mutex 保护共享资源:

var mu sync.Mutex
var count intfunc increment() {mu.Lock()count++mu.Unlock()
}

十二、总结与展望

Go 是一个简单而强大的语言,特别适合写高性能、高并发的应用。Java 开发者上手虽然有点门槛,但只要掌握了并发模型和一些核心特性,就能快速进入状态。

如果这篇文章对你有帮助,记得点赞、收藏、关注我!后续还会带来更多 Go 实战内容,比如写 HTTP 服务器、操作数据库等。咱们下次见!

附录

12.1 Go 语言标准库速查表

  • fmt:格式化输入输出
  • os:操作系统交互
  • net/http:HTTP 服务器和客户端
  • sync:并发控制

12.2 示例代码

HTTP 服务器
package mainimport ("fmt""net/http"
)func handler(w http.ResponseWriter, r *http.Request) {fmt.Fprintf(w, "Hello, Go 开发者!")
}func main() {http.HandleFunc("/", handler)http.ListenAndServe(":8080", nil)
}
并发计数器
package mainimport ("fmt""sync""time"
)var (mu   sync.Mutexcount int
)func increment() {mu.Lock()count++mu.Unlock()
}func main() {var wg sync.WaitGroupfor i := 0; i < 100; i++ {wg.Add(1)go func() {defer wg.Done()increment()}()}wg.Wait()fmt.Println("最终计数:", count) // 输出: 100
}

希望大家喜欢这篇文章!如果有任何问题,欢迎在评论区留言,我会第一时间回复! 😊

相关文章:

Go 语言语法精讲:从 Java 开发者的视角全面掌握

《Go 语言语法精讲&#xff1a;从 Java 开发者的视角全面掌握》 一、引言1.1 为什么选择 Go&#xff1f;1.2 适合 Java 开发者的原因1.3 本文目标 二、Go 语言环境搭建2.1 安装 Go2.2 推荐 IDE2.3 第一个 Go 程序 三、Go 语言基础语法3.1 变量与常量3.1.1 声明变量3.1.2 常量定…...

MySQL 复制与主从架构(Master-Slave)

MySQL 复制与主从架构&#xff08;Master-Slave&#xff09; MySQL 复制与主从架构是数据库高可用和负载均衡的重要手段。通过复制数据到多个从服务器&#xff0c;既可以实现数据冗余备份&#xff0c;又能分担查询压力&#xff0c;提升系统整体性能与容错能力。本文将详细介绍…...

水下成像机理分析

一般情况下, 水下环境泛指浸入到人工水体 (如水库、人工湖等)或自然水体(如海洋、河流、湖 泊、含水层等)中的区域。在水下环境中所拍摄 的图像由于普遍受到光照、波长、水中悬浮颗粒物 等因素的影响&#xff0c;导致生成的水下图像出现模糊、退 化、偏色等现象&#xff0c;图像…...

腾讯云智测试开发面经

1、投递时间线 2.20投递简历,3.11第一轮面试,3.30第二轮面试,4.4第三轮面试,4.10第四轮面试,4.11offer意向书 2、第一轮面试 第一轮面试技术面,面试官是导师,面试时长40多分钟 1)自我介绍 2)数组和列表的区别 3)了解哪些数据库 4)进程和线程的区别 5)了解哪…...

JVM类加载器详解

文章目录 1.类与类加载器2.类加载器加载规则3.JVM 中内置的三个重要类加载器为什么 获取到 ClassLoader 为null就是 BootstrapClassLoader 加载的呢&#xff1f; 4.自定义类加载器什么时候需要自定义类加载器代码示例 5.双亲委派模式类与类加载器双亲委派模型双亲委派模型的执行…...

@ComponentScan注解详解:Spring组件扫描的核心机制

ComponentScan注解详解&#xff1a;Spring组件扫描的核心机制 一、ComponentScan注解概述 ComponentScan是Spring框架中的一个核心注解&#xff0c;用于自动扫描和注册指定包及其子包下的Spring组件。它是Spring实现依赖注入和自动装配的基础机制之一。 Retention(Retention…...

rust Send Sync 以及对象安全和对象不安全

开头&#xff1a;菜鸟小明的疑惑 小明&#xff1a; “李哥&#xff0c;我最近学 Rust&#xff0c;感觉它超级严谨&#xff0c;啥 Send、Sync、对象安全、静态分发、动态分发的&#xff0c;我都搞晕了&#xff01;为啥 Rust 要设计得这么复杂啊&#xff1f;” 小李&#xff0…...

从一到无穷大 #44:AWS Glue: Data integration + Catalog

本作品采用知识共享署名-非商业性使用-相同方式共享 4.0 国际许可协议进行许可。 本作品 (李兆龙 博文, 由 李兆龙 创作)&#xff0c;由 李兆龙 确认&#xff0c;转载请注明版权。 文章目录 引言Glue的历史&#xff0c;设计原则与挑战Serverless ETL 功能设计Glue StudioGlue …...

【Redis】如何处理缓存穿透、击穿、雪崩

Redis 缓存穿透、击穿和雪崩是高并发场景下的典型问题&#xff0c;以下是详细解决方案和最佳实践&#xff1a; 一、缓存穿透&#xff08;Cache Penetration&#xff09; 问题&#xff1a;恶意请求不存在的数据&#xff08;如不存在的ID&#xff09;&#xff0c;绕过缓存直接访…...

区块链技术如何重塑金融衍生品市场?

区块链技术如何重塑金融衍生品市场&#xff1f; 金融衍生品市场一直是全球金融体系的重要组成部分&#xff0c;其复杂性和风险性让许多投资者望而却步。然而&#xff0c;随着区块链技术的兴起&#xff0c;这一领域正在经历一场深刻的变革。区块链以其去中心化、透明和不可篡改…...

实战打靶集锦-35-GitRoot

文章目录 1. 主机发现2. 端口扫描3. 服务枚举4. 服务探查5. 系统提权6. 写在最后 靶机地址&#xff1a;https://download.vulnhub.com/gitroot/GitRoot.ova 1. 主机发现 目前只知道目标靶机在192.168.56.xx网段&#xff0c;通过如下的命令&#xff0c;看看这个网段上在线的主机…...

Vue3 + Element Plus + AntV X6 实现拖拽树组件

Vue3 Element Plus AntV X6 实现拖拽树组件 介绍 在本篇文章中&#xff0c;我们将介绍如何使用 Vue 3 和 Element Plus 结合 antv/x6 实现树形结构的拖拽功能。用户可以将树节点拖拽到图形区域&#xff0c;自动创建相应的节点。我们将会通过简单的示例来一步步讲解实现过程…...

从零开始跑通3DGS教程:介绍

写在前面 本文内容 本文所属《从零开始跑通3DGS教程》系列文章&#xff0c;将实现从原始图像(有序、无序)数据开始&#xff0c;经过处理(视频抽帧成有序)&#xff0c;SFM&#xff0c;3DGS训练、编辑、渲染等步骤&#xff0c;完整地呈现从原始图像到新视角合成的全部流程&#x…...

聊聊Spring AI的Chat Model

序 本文主要研究一下Spring AI的Chat Model Model spring-ai-core/src/main/java/org/springframework/ai/model/Model.java public interface Model<TReq extends ModelRequest<?>, TRes extends ModelResponse<?>> {/*** Executes a method call to …...

将mysql配置成服务的方法

第一步&#xff1a;配置环境变量 1)新建MYSQL_HOME变量&#xff0c;并配置:C:\Program Files\MySQL\MySQL Server 5.6 MYSQL_HOME&#xff1a;C:\Program Files\MySQL\MySQL Server 5.6 2)编辑path系统变量&#xff0c;将%MYSQL_HOME%\bin添加到path变量后。配置path环境变量…...

GaussDB(for PostgreSQL) 存储引擎:ASTORE 与 USTORE 详细对比

GaussDB(for PostgreSQL) 存储引擎&#xff1a;ASTORE 与 USTORE 详细对比 1. 背景说明 GaussDB(for PostgreSQL) 是华为基于 PostgreSQL 开发的企业级分布式数据库&#xff0c;其存储引擎分为 ASTORE 和 USTORE 两种类型&#xff0c;分别针对不同场景优化。 2. 核心对比 (1)…...

英语口语 -- 常用 1368 词汇

英语口语 -- 常用 1368 词汇 介绍常用单词List1 &#xff08;96 个&#xff09;时间类气候类自然类植物类动物类昆虫类其他生物地点类 List2 &#xff08;95 个&#xff09;机构类声音类食品类餐饮类蔬菜类水果类食材类饮料类营养类疾病类房屋类家具类服装类首饰类化妆品类 Lis…...

SpringBoot+Vue 中 WebSocket 的使用

WebSocket 是一种在单个 TCP 连接上进行全双工通信的协议&#xff0c;它使得客户端和服务器之间可以进行实时数据传输&#xff0c;打破了传统 HTTP 协议请求 - 响应模式的限制。 下面我会展示在 SpringBoot Vue 中&#xff0c;使用WebSocket进行前后端通信。 后端 1、引入 j…...

关于依赖注入框架VContainer DIIOC 的学习记录

文章目录 前言一、VContainer核心概念1.DI(Dependency Injection&#xff08;依赖注入&#xff09;)2.scope(域&#xff0c;作用域) 二、练习例子1.Hello,World!步骤一&#xff0c;编写一个底类。HelloWorldService步骤二&#xff0c;编写使用低类的类。GamePresenter步骤三&am…...

LRU缓存是什么

LRU缓存是什么 LRU(Least Recently Used)即最近最少使用,是一种缓存淘汰策略。在缓存空间有限的情况下,当新的数据需要存入缓存,而缓存已满时,LRU 策略会优先淘汰最近最少使用的数据,以此保证缓存中存储的是最近最常使用的数据。 LRU缓存的工作原理 LRU 缓存的核心思…...

Qt常用控件第一部分

1.控件概述 Widget 是 Qt 中的核⼼概念. 英⽂原义是 "⼩部件", 我们此处也把它翻译为 "控件" . 控件是构成⼀个图形化界⾯的基本要素. 像上述⽰例中的, 按钮, 列表视图, 树形视图, 单⾏输⼊框, 多⾏输⼊框, 滚动条, 下拉框等, 都可以称为 "控件"…...

docker存储卷及dockers容器源码部署httpd

1. COW机制 Docker镜像由多个只读层叠加而成,启动容器时,Docker会加载只读镜像层并在镜像栈顶部添加一个读写层。 如果运行中的容器修改了现有的一个已经存在的文件,那么该文件将会从读写层下面的只读层复制到读写层,该文件的只读版本依然存在,只是已经被读写层中该文件…...

JMeter接口自动化发包与示例

前言 JMeter接口自动化发包与示例 近期需要完成对于接口的测试,于是了解并简单做了个测试示例&#xff0c;看了看这款江湖上声名远播的强大的软件-Jmeter靠不靠谱。 官网&#xff1a;Apache JMeter - Apache JMeter™ 1简介 Apache-Jmeter是一个使用java语言编写且开源&…...

INFINI Console 极限控制台密码忘记了,如何重置?

在使用 INFINI Console&#xff08;极限控制台&#xff09;时&#xff0c;可能会遇到忘记密码的情况&#xff0c;这对于管理员来说是一个常见但棘手的问题。 本文将详细介绍如何处理 INFINI Console 密码忘记的情况&#xff0c;并提供两种可能的解决方案&#xff0c;帮助您快速…...

Python运算符的理解及简单运用

免责声明 如有异议请在评论区友好交流&#xff0c;或者私信 内容纯属个人见解&#xff0c;仅供学习参考 如若从事非法行业请勿食用 如有雷同纯属巧合 版权问题请直接联系本人进行删改 前言 提示&#xff1a;这里可以添加本文要记录的大概内容&#xff1a; 提示&#xff1a;以…...

汇编学习之《jcc指令》

JCC&#xff08;Jump on Condition Code&#xff09;指的是条件跳转指令&#xff0c;c中的就是if-else, while, for 等分支循环条件判断的逻辑。它包括很多指令集&#xff0c;各自都不太一样&#xff0c;接下来我尽量将每一个指令的c 源码和汇编代码结合起来看&#xff0c;加深…...

k8s的容器操作指令

几个命令目录 1、kubectl exec -n ithmp-prod -it <pod-name> /bin/bash命令组成部分使用场景注意事项 2、docker ps基本用法输出格式常用选项1. 列出所有容器&#xff08;包括已停止的&#xff09;2. 显示最近创建的容器3. 显示最近创建的几个容器4. 显示容器的详细信息…...

从零构建大语言模型全栈开发指南:第四部分:工程实践与部署-4.3.3低代码开发:快速构建行业应用(电商推荐与金融风控案例)

👉 点击关注不迷路 👉 点击关注不迷路 👉 点击关注不迷路 文章大纲 从零构建大语言模型全栈开发指南-第四部分:工程实践与部署4.3.3 低代码开发:快速构建行业应用(电商推荐与金融风控案例)1. 低代码与AI结合的核心价值2. 电商推荐系统案例2.1 技术架构与实现2.2 性能…...

基于vue框架的智能服务旅游管理系统54kd3(程序+源码+数据库+调试部署+开发环境)带论文文档1万字以上,文末可获取,系统界面在最后面。

系统程序文件列表 项目功能&#xff1a;用户,景点信息,门票预订,酒店客房,客房预订,旅游意向,推荐景点,景点分类 开题报告内容 基于Vue框架的智能服务旅游管理系统开题报告 一、研究背景与意义 1.1 行业现状与挑战 传统系统局限性&#xff1a;当前旅游管理系统普遍存在信息…...

用Python实现TCP代理

依旧是Python黑帽子这本书 先附上代码&#xff0c;我在原书代码上加了注释&#xff0c;更好理解 import sys import socket import threading#生成可打印字符映射 HEX_FILTER.join([(len(repr(chr(i)))3) and chr(i) or . for i in range(256)])#接收bytes或string类型的输入…...