首页  >  文章  >  后端开发  >  这就是我在两周内学到的关于 Go 的全部内容!

这就是我在两周内学到的关于 Go 的全部内容!

Barbara Streisand
Barbara Streisand原创
2024-10-31 04:27:02767浏览

This is all what I

当你需要学习新东西时你的方法是什么?我有一个非常具体的,我在学习 Golang 时再次测试了它!

要讲的内容太多了,但我的目的是列出我发现有用的并且我专门花时间正确学习的内容。

目录

  • 1.序言
  • 2. 认识 CLI
    • 2.1 CLI:go mod
    • 2.2 CLI:运行
  • 3. 比较不同的语法
    • 3.1 语法:类/结构体和 API 封装
    • 3.2 语​​法:接口实现很奇怪 AS FUC*
  • 4. Stdlib:绝对是一个很棒的工具包
    • 4.1 包:原始类型
    • 4.2 包:有用的东西
  • 5. Go 中的测试就是这么简单
    • 5.1 测试:基本测试
    • 5.2 测试:Jetbrains 样板
    • 5.3 测试:运行测试
  • 6.当心循环导入
  • 7.推迟这个,推迟那个……但是,什么是推迟?
  • 8.菜鸟错误管理
  • 9.结论壮举:低延迟编码挑战

1. 序言

在过去的两周里,我一直在使用 Golang 学习和构建小型应用程序。目前,通过许多直播已经完成了近 50 小时的代码,能够学到一些我之前在语言方面遇到一些小问题的东西真是太棒了。

在这两周的旅程中,我精心设计了:

  • 一个小而非常简单的外壳
  • Redis 基本实现
  • HTTP 1.1 协议实现
  • DNS 服务器实现
  • 以及一家非常酷的公司的工作测试(将在本文末尾提供)。

这一切都是因为我的老板再次要求我学习一项新技术来处理一些 ScyllaDB PoC 和演示...我对这个决定不太满意,但是好吧,这是我的工作。

去年我一直在学习 Rust,它对我来说可能仍然太复杂,但我学到了一些非常酷的概念,这些概念让我转向 Go 的过程非常顺利!

在这篇文章中,我将为您提供一些技巧和建议,以加快您的学习流程。

2. 认识 CLI

我是一名 PHP 开发人员,我习惯了有史以来最好的 CLI(是的,它是 Artisan),但是在我作为开发人员的旅程中,我经历过一些很棒的项目,其中许多都是......:

  • 货物(生锈)
  • NPM (JS)
  • 作曲家 (PHP)
  • 等等...

当我进入 Go 环境时,它开始成为一个真正的问题。至少对我来说,Golang 在工具和文档方面的开发体验还可以好很多。考虑到这一点,我决定从一开始就学习必须学习的 3 个命令。

记住:这只是一个带有我自己解释的演练。如果您需要详细信息,请打开文档:)
另外:go docs 很糟糕,请有人在那里放一个语法荧光笔

2.1 CLI:go mod

根据您是否想要模块化应用程序或拥有一个有组织的环境,这将是最有用的命令。

go mod 命令管理项目中的所有依赖项,并负责自动删除不再使用的任何内容。

首先,在新的空文件夹中,让我们使用 go mod init 在项目内初始化一个新模块:

mkdir go-fodase
cd go-fodase

# go mod init <module-name>
go mod init github.com/danielhe4rt/go-fodase

这将在项目根目录中创建一个名为 go.mod 的新文件,它基本上是目前的内容:

  • 模块名称
  • 您的 Go 版本

这是文件,如果您想自己检查一下:

# folder: ~/go-fodase
cat go.mod

# module github.com/danielhe4rt/gofodase
# 
# go 1.23.2

之后,我真正喜欢的下一个东西是 go mod tidy,它基本上添加了所有缺失的依赖项并删除了未使用的依赖项。

go mod tidy

第二个只是为了让您记住这个存在并且非常有用!也许你的环境每次都会运行它,你会习惯看到导入消失:p

2.2 CLI:运行

这可能是您将使用的最常用命令,因为您必须运行项目,但它的工作原理如下:

  • 您应该指向包含 main() 函数的文件。
  • 此文件不必位于文件夹的根目录中。

关于这个命令最重要的一点是,当你运行 go run 命令时,它会在当前目录中查找 go.mod 文件,并将其用作映射整个项目(导入、包)的基础。 , ETC)。以下是一些示例:

# go run <your-main-file>

# Environment 1
# .
# ├── go.mod
# └── main.go
go run app.go

# Environment 2
# .
# ├── go.mod
# └── src
#     └── main.go
go run src/app.go

这是我们的 app.go 内容:

package main

import(
    "fmt"
)

func main () {
    fmt.Println("whats up! don't forget to like this article <3")
}

现在您已经了解了执行项目的基础知识!从字面上看,你好世界!

3. 比较不同的语法:

我对 Go 的问题一直是它的编写方式,但经过几个小时的编码后,我意识到它比我想象的要简单。正如您可能已经猜到的,我拥有深厚的 PHP 背景和一些 Rust 经验。

当我在 2023 年开始学习 Rust 时,幸运的是,我的忠实粉丝 Nuno Maduro(Laravel)做了一个名为“PHP for Rust 开发人员”的演讲,这给了我一些基本的介绍语法给了我一些喘息的空间,而我完全被Rust踩踏了

总之,当时对我有用,为什么不做一些比较呢?

3.1 语法:类/结构体和 API 封装

在 OOP 中,我们有类,这是一种将代码抽象为小块的非常酷的方式,并且您拥有“类似的”东西。 Golang 可以被视为一场奥德赛,因为它可以是一个史诗般的开发,可以将环境变成你想要的任何样子。

请记住,Golang 是一种“高级语言”,它提供“系统级”语法,使您可以轻松地使用“低级”实现。

Go语法下,你可以

  • [结构] 通过在类型前面加上前缀、添加“类/结构”名称,然后添加结构后缀来定义结构。
  • [封装] 通过以 UpperCaseLowerCase 名称开头来定义与类/结构相关的元素的暴露。
    • [Visibility: "public"]:将项目名称设置为大写。
    • [Visibility: "private/protected"]:将项目名称设置为小写。

您可以将其用于:结构体、结构体字段、结构体方法。仔细看看:

mkdir go-fodase
cd go-fodase

# go mod init <module-name>
go mod init github.com/danielhe4rt/go-fodase

在 Rust 中,你有一个更明确的方法(更像 oop 的语言),其中:

  • [Struct] 使用前缀 struct 定义一个结构,添加您的“类/结构”名称即可。
  • [封装] 如果你想让某些东西对其他“板条箱”公开,你应该在你想要公开的代码部分添加 pub 前缀。
# folder: ~/go-fodase
cat go.mod

# module github.com/danielhe4rt/gofodase
# 
# go 1.23.2

我想让 PHP、Java 等内容变得明确,但如果你停下来想想编写的代码更少,但这也会影响可读性。

3.2 语​​法:接口实现很WEIRD AS FUC*

说实话,我是那种会尝试将 LARAVEL 放入 Go 环境中的人,我不知道,但这已经在 Goravel 中完成了。不管怎样,我真的很喜欢使用“接口/契约驱动开发”,的想法,并且这是我第一次在一种语言中陷入困境。

在 Go 中,接口并不是在结构/类中“实现”,对于像我这样的 OOP 人员来说,让这样的设计决策融入我的头脑真是太疯狂了。看看预期的结果:

mkdir go-fodase
cd go-fodase

# go mod init <module-name>
go mod init github.com/danielhe4rt/go-fodase

现在,说到去:你在结构内部没有“接口”的显式实现,那就是,嗯... 奇怪?相反,您只需实现接口所需的方法,这些方法将在编译时为您进行检查。公平地说,这是一种编译语言,它永远不会成为问题,但我正在谈论我对开发者体验
的看法

# folder: ~/go-fodase
cat go.mod

# module github.com/danielhe4rt/gofodase
# 
# go 1.23.2

无论如何,只要花一些时间用该语言编码,您就会习惯它。现在,让我们来谈谈基础环境为您提供什么而无需下载任何东西!

4. Stdlib:绝对是一个很棒的工具包

现在我正在谈论Go通过标准库为您提供的一切,而无需下载第三方包。以下是一些按时间顺序排列的时间表:

  • 第一天:什么?为什么不像 JS/Java 那样类型包含所有方法? (我讨厌他们两个)
  • 第一周:等等,也许这很好(在了解了原始类型的包之后)
  • 第二周:什么?为什么其他语言默认没有这么好的库?

我不是在开玩笑,每天我探索 Go 时,我都会在标准库下发现一些很酷的库。那么,让我们开始讨论原始类型。

4.1 包:原始类型

与 PHP 一样,许多其他语言(Rust、Java、JS 等)不同,Golang 需要 “helper” 函数来执行大多数相关的 类型操作。我们可以将它们视为“贫血”类型,因为它们没有附加的“实用性”。

go mod tidy

因此,如果您正在使用 “字符串”类型,您可以使用其他软件包(如 strconv 或 strings)来操作它!但这里有一条黄金法则,永远不要忘记要查看哪个包:如果您的类型是字符串,请查找具有复数名称的相同包!

简而言之,这将为您提供与 []Type 和 Type:

相关的函数
  • 字符串类型 -> import ("strings") 用于以下操作:Contains()Upper()Split() ...
  • 字节类型 -> import ("bytes") 用于 Include()Compare()Split() ...
  • 等操作
  • 等等!

看一下代码,方便自己验证:

# go run <your-main-file>

# Environment 1
# .
# ├── go.mod
# └── main.go
go run app.go

# Environment 2
# .
# ├── go.mod
# └── src
#     └── main.go
go run src/app.go

这应该很简单,但我挣扎了一段时间,直到进入我的脑海。也许使用 Laravel 及其辅助函数太多年让我忘记了在没有框架的情况下编码是多么困难 :D

4.2 包:有用的东西

在探索工具和项目时,我对许多项目都有了很好的介绍,我想列出每个项目以及我使用过的库:

  • 构建您自己的 Shell 挑战:
    • 套餐:
      • fmt: I/O 库(扫描/读取并在屏幕上写入内容)
      • os: 直接与您的操作系统对话的函数和助手。
      • strconv:将特定数据类型转换为字符串或将字符串转换为任何定义的类型。
  • 构建您自己的 (HTTP|DNS) 服务器挑战:
    • 套餐:
      • net: 与网络 I/O 协议(如 HTTP、TCP、UDP 和 Unix Domain Sockets)的集成层
      • [之前的套餐...]
  • 中级家庭作业任务分配?
    • 套餐:
      • flag: 将 CLI 参数捕获到变量中
      • log: 将 Log 的频道添加到您的应用程序
      • 加密/兰特:安全加密随机生成器
      • 数学/兰特:数学数字随机生成器
      • 时间:持续时间/时间库

这是所有包实现的可滚动视图,以便您可以查看它们。这里有很多很酷的 std 包可以引用。

注意:这是很多代码! :p
不要忘记评论您最喜欢的功能(除了 goroutine 和通道):p

mkdir go-fodase
cd go-fodase

# go mod init <module-name>
go mod init github.com/danielhe4rt/go-fodase

说真的,这太棒了!那么,现在让我们继续测试吧。

5. Go 中的测试就是这么简单

在我使用 Go 的第二个项目中,我看到了在创建 Requests 和 Responses 对象时学习测试的机会。在 PHP 环境中,您可能正在使用第三方库,例如 PHPUnit 或 Pest。正确的?在 Go 环境中,这简单!您需要做的就是:

  • 在包内创建一个文件: 在 person.go 中,您将编写要测试的函数;
  • 为您的包创建一个测试文件:** 创建一个名为 person_test.go 的文件并开始编写您自己的测试!

假设我们的包文件夹中有 requests.go 和 requests_test.go,其中 requests.go 是:

# folder: ~/go-fodase
cat go.mod

# module github.com/danielhe4rt/gofodase
# 
# go 1.23.2

5.1 测试:基本测试

如果 (t *Testing.T).Errorf() 未在测试函数中调用,则 Go 中的测试被视为通过(绿色)。它还遵循前面介绍的相同封装概念:

  • 测试函数大写字母开头由测试运行者识别
  • 测试函数小写字母开头的将被忽略(通常是辅助函数)
mkdir go-fodase
cd go-fodase

# go mod init <module-name>
go mod init github.com/danielhe4rt/go-fodase

您可以做自己的辅助函数来测试。只要确保在这些测试中不要侵入模块域即可!

5.2 测试:Jetbrains 样板

我从第一天起就开始使用Goland,所以大多数事情对我来说都更容易。因此,每次我开始新的测试时,我都会得到这个带有默认并行运行(goroutines)的 Unity 测试结构的样板。

# folder: ~/go-fodase
cat go.mod

# module github.com/danielhe4rt/gofodase
# 
# go 1.23.2

5.3 测试:运行测试

好的,现在我们知道在 Go 中编写测试是多么容易,但是运行它们怎么样? 简单的任务!您需要做的就是导航到包文件夹并运行:

go mod tidy

请写下一些对你的东西的测试。如果你解耦所需的东西,这并不难:p

6.谨防循环导入

在我过去几年的开发过程中,我一直尝试以适合我的需求的方式模块化我的所有项目,而不是陷入“干净的拱门”或“领域驱动设计”的东西。然而,在我第一次尝试拆分包时,我收到了“循环导入”错误,并心想:我多久没见过这样的东西了?

在 PHP 的 2 年里,我遇到了同样的导入地狱问题,你无法在特定流程中不导入同一个文件两次。那是在我遇到 PSR-4(自动加载)之前(它永远改变了我的 PHP 时代!!),而现在,几年前,我在 Go 中遇到了这个问题。

让我们考虑一个循环导入的场景:

# go run <your-main-file>

# Environment 1
# .
# ├── go.mod
# └── main.go
go run app.go

# Environment 2
# .
# ├── go.mod
# └── src
#     └── main.go
go run src/app.go

当您尝试在 Go 中编译标记循环导入的内容时,您将收到如下错误:

package main

import(
    "fmt"
)

func main () {
    fmt.Println("whats up! don't forget to like this article <3")
}

此时此刻,您必须开始分解您的依赖项/包以避免它。

TLDR:不要在会被多次加载的地方导入同一个包。

7. 推迟这个,推迟那个……但是,什么是推迟?

我没有查,但这是我第一次在编程语言中看到保留字 defer。而且由于它不是“通用保留字”的一部分,所以我整整忽略了它!

然后,我的一位同事 Dusan 在看到我在 Go 语言上挣扎了几个小时后,给我上了一堂 Go 语言的内存管理课。 (是的,这是一个大声喊叫:p)

事情是:每当你打开某个东西的缓冲区/连接时,你应该关闭它!我记得2014年我使用MapleStory服务器(Java)时,最常见的问题是内存泄漏,仅仅是因为开发人员没有关闭与数据库的连接。

这可以忘记!但是通过Code Review就不行了哈哈

这是一个 Java 示例:

mkdir go-fodase
cd go-fodase

# go mod init <module-name>
go mod init github.com/danielhe4rt/go-fodase

在编写 Golang 代码时,他们提供了这个延迟属性,以便您记住在打开内容后立即将其关闭。

Defer 代表“尊重”,这是在代码的特定部分执行结束后“清理”资源的一种方式。

# folder: ~/go-fodase
cat go.mod

# module github.com/danielhe4rt/gofodase
# 
# go 1.23.2

您还可以在一个函数内有多个延迟,并且 DEFER ORDER 很重要!如果您推迟 database2 然后推迟 database1,两个进程都将以相同的顺序进行清理。

go mod tidy

这是一个非常简单的方法不会搞砸防止你的项目出现内存泄漏。请记住在您直播任何内容时使用它。

8.菜鸟错误管理

错误处理首先类似于:检查您正在使用的函数是否返回错误类型并每次时间验证它!这是我正在谈论的示例:

# go run <your-main-file>

# Environment 1
# .
# ├── go.mod
# └── main.go
go run app.go

# Environment 2
# .
# ├── go.mod
# └── src
#     └── main.go
go run src/app.go

说实话,我讨厌这种语法。然而,它是语言的一部分,并且是您在编码期间会遇到的东西。

有错误的函数可能会返回错误或 (T, error),幸运的是 Go 不会让你忘记这一点。

package main

import(
    "fmt"
)

func main () {
    fmt.Println("whats up! don't forget to like this article <3")
}

用 err != nil 向你的代码发送垃圾邮件,我保证你会没事的! :D

9. 结论壮举:低延迟编码挑战

除了为了了解环境而付出的所有压力和时间之外,与我的 Twitch 观众一起学习一门新语言是一个很酷的挑战。他们中的许多人长期以来一直要求我检查一下,我们就在这里。

所有这些都反映了我个人在这门语言上的发展经历,目的是分享我在这两周的学习过程中所经历的事情。

9.1 奖励:编码挑战

最近,我的队友要求我完成 ScyllaDB 挑战,它教会了我很多关于并行性、池和速率限制的知识。这是许多公司为了让自己的产品表现更好而面临的挑战!

挑战的目标是创建一个小型 Go 命令行应用程序,将一些随机数据插入 ScyllaDB,同时限制请求数量。

您可以在这里找到存储库挑战:github.com/basementdevs/throtdling-requests-scylla-test。我们还招人呢!您可以在我们的职业部分找到空缺职位!

感谢您的阅读!我希望这篇文章能为学习 Golang 提供有价值的见解。欢迎分享您的想法或经验。

以上是这就是我在两周内学到的关于 Go 的全部内容!的详细内容。更多信息请关注PHP中文网其他相关文章!

声明:
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系admin@php.cn