使用Golang Air实现热重启

Air是一个命令行实用程序,专为在开发过程中实时重新加载Go应用程序而设计。它是一种工具,使Go应用程序能够实时重新加载。

在编码时,实时重新加载可以让开发人员实时查看他们的更改。这样可以节省时间,因为无需在更改后手动停止和重新启动服务器。某些Go live重新加载框架可以在源代码更改后自动重新加载您的应用程序。本文将演示如何使用Air库在Go中实时重新加载。

Golang Air图书馆简介

Air是一个命令行实用程序,专为在开发过程中实时重新加载Go应用程序而设计。它是一种工具,使Go应用程序能够实时重新加载。

除了Air之外,Go的其他知名实时充值框架包括Fresh和Realize。它们的运行方式类似,在检测到源代码更改时自动重新生成并重新启动应用程序。

  • Fresh是一个命令行工具,旨在与任何Go Web服务器一起使用,轻松集成到您的构建过程中。
  • Realize是一个基于Go的构建系统,为Go应用程序提供实时重新加载功能。

鉴于这些选项在功能上的相似性,在Go项目中使用哪个框架的选择很大程度上取决于个人喜好。对每一种方法进行试验,以确定哪种方法对您的工作流程最直接或最直观。

什么是实时充值?

实时重新加载是一项开发功能,每当您更改源代码时,它都会自动刷新应用程序或服务器。它在开发和调试期间特别有用,因为它消除了每次修改代码时手动停止和重新启动应用程序的需要。

何时实施实时重载?

实时重新加载在各种情况下都是有益的,包括:

网站开发

实时重新加载通常用于 Web开发,用于客户端(HTML、CSS、JavaScript)和服务器端(后端代码)更改。保存文件时,网页会自动刷新以反映最新更改,而无需手动刷新。

前端框架

React、Angular和Vue等前端框架通常带有内置或易于集成的工具,支持实时重新加载。这加快了开发过程,并允许开发人员立即看到用户界面的变化。

后端开发

在后端开发期间,当对服务器端代码进行更改时,实时重载可用于自动重新启动服务器。这在 Express (Node.js)、Django (Python) 等框架中很常见。

跨平台开发

实时重新加载在跨平台开发场景中很有价值,例如使用 React Native或Flutter 等框架进行移动应用程序开发。对代码的更改可能会在连接的设备或仿真器上触发自动更新。

Go语言 (Golang)

Go编程语言在开发过程中对实时重载有很好的支持。像ginfreshair这样的工具在Go社区中很受欢迎。它们监控代码更改并自动重新构建和重新启动Go应用程序,从而提供无缝的开发体验。

使用示例:gin

go get -u github.com/codegangsta/gin
gin run main.go

使用示例:air

go get -u github.com/cosmtrek/air
air

Go中的实时重载与热重载

在Go中,术语"实时重新加载"是指无需手动停止和重新启动即可自动刷新和更新应用程序的能力。

一个称为"热重载"的类似概念专门涉及在应用程序仍在运行时更新其代码,而不会中断其当前状态或任何正在进行的进程。

实时重载和热重载在开发中都是有利的,可以更快地迭代和测试代码更改,而无需手动中断和重新启动。根据应用程序的复杂性,实现热重载可能不可行,或者可能会带来更多挑战。

Go和Gin项目缺乏对实时重新加载功能的固有支持。因此,让我们探讨一下如何配置Air库以在Go和Gin项目中实现实时重载。

将Golang Air与Gin Gonic一起使用的6个步骤

第1步:安装Gin Gonic和Air

打开终端并运行以下命令以安装Gin Gonic和Air:

# Install Gin Gonic
go get -u github.com/gin-gonic/gin
# Install Air
go get -u github.com/cosmtrek/air

第2步:创建一个简单的杜松子酒应用程序

创建一个新文件,以以下内容命名:main.go

// main.go
package main

import (
"github.com/gin-gonic/gin"
)

func main() {
// Create a new Gin router
router := gin.Default()

// Define a route
router.GET("/", func(c *gin.Context) {
c.JSON(200, gin.H{
"message": "Hello, Gin!",
})
})

// Run the server on port 8080
router.Run(":8080")
}

步骤3:创建Air配置文件

创建一个包含以下内容的文件:air.toml

# air.toml
root = "."
tmp_dir = "tmp"
build_cmd = "go build -o ./tmp/main ."
run_cmd = "./tmp/main"

步骤4:使用Air运行应用程序

在终端中,导航到项目目录并使用Air运行应用程序:

air

这将启动您的杜松子酒应用程序并实时重新加载。当您更改代码并保存文件时,Air将自动检测更改并重新启动服务器。

步骤5:测试应用程序

打开您的网络浏览器并转到 http://localhost:8080。您应该会看到JSON响应:

{"message":"Hello, Gin!"}

第6步:进行更改并查看实时重新加载的实际操作

对文件main.go进行一些更改,保存它,并观察Air如何自动重新启动服务器。检查浏览器以查看更新的响应,而无需手动重新启动应用程序。

将Golang Air与Echo一起使用的6个步骤

第1步:安装Echo和Air

打开终端并运行以下命令以安装Echo和Air:

# Install Echo
go get -u github.com/labstack/echo/v4

# Install Air
go get -u github.com/cosmtrek/air

步骤2:创建简单的Echo应用程序

创建一个新文件main.go,以以下内容命名:

// main.go
package main

import (
"github.com/labstack/echo/v4"
"net/http"
)

func main() {
// Create a new Echo instance
e := echo.New()

// Define a route
e.GET("/", func(c echo.Context) error {
return c.JSON(http.StatusOK, map[string]string{
"message": "Hello, Echo!",
})
})

// Start the server on port 8080
e.Start(":8080")
}

步骤3:创建Air配置文件

创建一个包含以下内容的文件:air.toml

# air.toml
root = "."
tmp_dir = "tmp"
build_cmd = "go build -o ./tmp/main ."
run_cmd = "./tmp/main"

步骤4:使用Air运行应用程序

在终端中,导航到项目目录并使用Air运行应用程序:

air

步骤5:测试应用程序

打开您的网络浏览器并转到 http://localhost:8080。您应该会看到JSON响应:

{"message":"Hello, Echo!"}

第6步:进行更改并查看实时重新加载的实际操作

如上。

将空气与纤维一起使用的6个步骤

第1步:安装光纤和空气

打开终端并运行以下命令以安装Fiber and Air:

# Install Fiber
go get -u github.com/gofiber/fiber/v2
# Install Air
go get -u github.com/cosmtrek/air

步骤2:创建简单的光纤应用程序

创建一个新文件,以以下内容命名:main.go

// main.go
package main

import (
"github.com/gofiber/fiber/v2"
)

func main() {
// Create a new Fiber instance
app := fiber.New()

// Define a route
app.Get("/", func(c *fiber.Ctx) error {
return c.JSON(map[string]string{
"message": "Hello, Fiber!",
})
})

// Start the server on port 8080
app.Listen(":8080")
}

步骤3:创建Air配置文件

创建一个包含以下内容的文件:air.toml

# air.toml
root = "."
tmp_dir = "tmp"
build_cmd = "go build -o ./tmp/main ."
run_cmd = "./tmp/main"

步骤4:使用Air运行应用程序

在终端中,导航到项目目录并使用Air运行应用程序:

air

这将通过实时重新加载启动您的光纤应用程序。当您更改代码并保存文件时,Air将自动检测更改并重新启动服务器。

步骤5:测试应用程序

打开您的网络浏览器并转到 http://localhost:8080。您应该会看到JSON响应:

{"message":"Hello, Fiber!"}

第6步:进行更改并查看实时重新加载的实际操作

如上。

将Golang Air与Docker容器一起使用的4个步骤

在Go应用程序中使用 Docker容器的实时重载的主要好处之一是,它允许您快速迭代代码,而无需每次都停止和启动容器。

这在容器中制作和验证应用程序时变得特别有利,有助于快速、轻松地识别和解决问题。

若要将实时重载库与Docker集成,必须在Docker容器中为本地源代码目录建立卷挂载。此设置使Air库能够监视代码更改,并根据需要自主刷新服务器。

第1步:使用安装和运行Air的说明创建一个Dockerfile

FROM golang:latest

# Set the current working directory inside the container
WORKDIR /app

# Copy go.mod and go.sum files to the workspace
COPY go.mod go.sum ./

# Download all dependencies
RUN go mod download

# Copy the source from the current directory to the workspace
COPY . .

# Build the Go app
RUN go build -o main .

# Expose port 8080 to the outside world
EXPOSE 8080

# Command to run the executable
CMD ["air"]

第2步:创建文件.air.toml

在项目的根目录中创建一个包含以下内容的文件:.air.toml

root = "."
testdata_dir = "testdata"
tmp_dir = "tmp"

[build]
args_bin = []
bin = "./tmp/main"
cmd = "go build -o ./tmp/main ."
delay = 1000
exclude_dir = ["assets", "tmp", "vendor", "testdata"]
exclude_file = []
exclude_regex = ["_test.go"]
exclude_unchanged = false
follow_symlink = false
full_bin = ""
include_dir = []
include_ext = ["go", "tpl", "tmpl", "html"]
kill_delay = "0s"
log = "build-errors.log"
send_interrupt = false
stop_on_error = true

[color]
app = ""
build = "yellow"
main = "magenta"
runner = "green"
watcher = "cyan"

[log]
time = false

[misc]
clean_on_exit = false

[screen]
clear_on_rebuild = false

步骤3:构建Docker镜像

docker build -t airy-app .

步骤4:在Docker容器中运行服务器

docker run -p 8080:8080 -v $PWD:/app airy-app
  • docker run:这是用于运行Docker容器的命令。
  • p 8080:8080:此选项将主机上的端口8080映射到容器中的端口8080。它允许外部系统通过端口8080访问容器内运行的应用程序。
  • v $PWD:/app:此选项将主机上的当前工作目录 () 挂载到容器内的目录。这是一个卷挂载,它允许容器访问主机当前工作目录中的文件和目录。对主机或容器中的文件所做的更改将反映在两者中。$PWD/app
  • airy-app:这是您正在运行的Docker映像的名称。它指定将从中创建容器的映像。

docker run命令从映像创建并运行容器。它将端口8080从主机映射到容器中的端口8080,从而允许对应用程序进行外部访问。它还将主机上的当前工作目录挂载到容器内的目录,从而促进主机和容器之间的数据共享。airy-app/app

在Go中使用Live Reload的利弊

优点

实时重新加载是一种开发工具,可显着提高编码过程的效率。每当对源代码进行更改时,它都可以自动和即时更新应用程序,而无需手动重新启动。这就是为什么它是有利的:

  • 提高开发速度: 传统开发通常涉及停止应用程序并重新启动它以查看代码更改生效。实时重新加载通过在保存代码后立即动态应用更改来消除此延迟,从而加快开发工作流程。
  • 最大限度减少停机时间: 如果没有实时重新加载,开发人员经常会遇到停机,等待应用程序在修改后重新启动。实时重新加载可最大限度地减少停机时间,使开发人员能够专注于编码而不会中断。
  • 便于调试: 实时重新加载是一个非常宝贵的调试工具。它通过在进行更改时自动刷新应用程序来加快问题的识别和解决。这种即时反馈循环加快了调试过程。
  • 高效测试:连续和自动重新加载有助于测试不同的场景,确保在不需要人工干预的情况下对更改进行彻底测试。
  • 无缝容器开发:在Docker等容器化环境中,实时重新加载对于快速适应更改很有价值,可以更轻松地识别和解决容器化应用程序中的问题。
  • 复杂项目的理想选择: 在具有众多依赖项或延长启动时间的复杂项目中,实时重新加载被证明特别有益。它通过提供对代码更改影响的实时可见性来简化开发过程,而无需重复手动干预。

从本质上讲,实时重新加载是一种节省时间的机制,可以简化开发工作流程,减少停机时间,帮助调试,并且被证明对于具有复杂结构或扩展启动过程的项目特别有利。

缺点

  • 资源密集型:实时重新加载工具通常会消耗额外的系统资源来监视和重新加载应用程序。这可能会导致开发过程中的内存和CPU使用率增加。
  • 潜在的意外副作用:自动重新加载可能会引入意外行为,尤其是在复杂的应用程序中,因为它会中断现有状态和正在进行的进程。开发人员需要谨慎对待潜在的副作用。
  • 兼容性挑战:集成实时重新加载功能可能需要调整项目结构或依赖关系。某些项目可能与某些实时重新加载工具不兼容。
  • 构建时间开销:在实时重新加载期间重建和重新启动应用程序的过程会略有延迟。虽然这种延迟通常很小,但随着时间的推移,它可能会累积起来,并影响整体开发体验。
  • 对特定工具的依赖性:实时重新加载通常由特定的工具或库(例如,Air、Fresh)促进。依赖于这些工具会引入可能需要管理和更新的依赖关系。

实时重新加载可以通过提供有关代码更改的快速反馈来显著改善开发体验。但是,开发人员应该意识到潜在的缺点,包括资源消耗、意外的副作用以及在某些项目环境中仔细集成的必要性。使用实时重新加载的决定应基于项目的具体需求和特点。

结论

综上所述,实时重载在开发过程中的重要性怎么强调都不为过。它可以作为更高效工作流程的催化剂,使开发人员能够实时见证其代码更改的影响。

就Go (Golang) 而言,像Air这样的工具通过自动化重建和重启过程,培养持续的开发体验,发挥着关键作用。这不仅加快了迭代速度,还提高了整体生产力,因为开发人员可以专注于编码,而不会因人工干预而造成中断。

从本质上讲,以Air等工具为代表的实时重新加载是现代开发环境中不可或缺的资产,有助于实现更快的反馈循环和更灵敏的编码体验。

golang runtime: program exceeds 10000-thread limit问题解决,控制goroutines数量

这个问题是因为golang运行时最大进行中线程数限制在10000个。

可以用创建线程池的方式限制同时运行的线程数量。

比如,带有缓冲的channel。

func doThing(d interface{}){
    // 一些业务逻辑
}
func main() {
    var data [1000]int // 假设有1000   
    poolSize := runtime.NumCPU() // 获取cpu核sem := make(chan struct{}, poolSize)
    for _, d := range data {
        sem <- struct{}{}
        go func(d int){
            doThing(d)
            <-sem
        }(d)
    }
}

以上示例中,sem<- struct{}{}操作,在sem通道满的时候会暂停等待空出,因此保证里go func(d int)同时只有poolSize个。

import (
    "context"
    "golang.org/x/sync/semaphore"
)

func doThing(d interface{}){
    // 一些操作
}

func main() {
    data := [1000]int // 假设有1000个poolSize := runtime.NumCPU() // 获取cpu数核量sem := semaphore.NewWeighted(poolSize)
    for _, d := range data {
        sem.Acquire(context.Background(), 1) // 获取1个锁go func(d interface{}){
            doThing(d)
            sem.Release(1) // 释放1个锁
        }(d)
    }
}

以上示例基本思路与上一个channel缓冲示例一样,通过获取池子中的锁来控制并发数量。

Go语言教程之边写边学:基础练习:如何提高 Golang 应用程序的性能?

Go应用程序的性能可能取决于多个因素,包括代码的复杂性、使用的资源量以及运行它的底层硬件。然而,Go以其快速的执行速度和对系统资源的高效利用而闻名,这使其成为构建高性能应用程序的热门选择。

  • 使用性能分析工具:Golang提供了多种性能分析工具,包括内置的pprof包,它可以帮助您识别代码中的性能瓶颈。使用这些工具确定代码的哪些部分花费的时间最多,并对其进行优化。
  • 使用适当的数据结构:Golang提供了多种内置数据结构,例如映射、切片和数组,这些结构针对性能进行了优化。根据您的需求使用适当的数据结构,以确保最佳性能。
  • 避免不必要的内存分配:Golang的垃圾收集器很高效,但不必要的内存分配仍然会减慢您的应用程序速度。通过重用对象并预分配切片和数组来最大程度地减少内存分配。
  • 使用并发:Golang内置的并发功能,例如goroutines和channels,可以轻松编写可以利用多核处理器的并发程序。使用并发性来执行并行计算,提高应用程序的效率。
  • 优化数据库查询:如果应用程序使用数据库,请优化查询以最大程度地减少到数据库的往返次数,并减少需要传输的数据量。
  • 使用缓存:缓存可以减少需要执行的计算和数据库查询的数量,从而显著提高应用程序的性能。使用缓存将经常访问的数据存储在内存中。
  • 监视应用程序:监视应用程序在生产中的性能,以识别问题并优化性能。使用Prometheus或Grafana等工具监控CPU使用率、内存使用率和请求延迟等指标。

通过遵循这些最佳实践,您可以提高Golang应用程序的性能,并为您的用户提供更好的用户体验。

golang中有trait吗?

在Go语言中,并没有直接支持trait的概念。Go语言的设计哲学强调的是简单和直接,而不是通过继承或组合来复用代码。

然而,你可以使用Go语言的接口(interface)和嵌入(embedding)机制来实现类似trait的功能。接口定义了一组方法的集合,一个类型只需要实现这些方法就可以被认为是实现了该接口。嵌入则允许一个结构体嵌入另一个结构体,并继承其方法和字段。

通过接口和嵌入的组合,你可以在Go中实现类似于trait的功能。你可以定义一个接口,其中包含了一些方法,然后让一个类型实现这些方法,从而满足该接口的要求。同时,你可以将该类型嵌入到其他结构体中,以便在更大的上下文中使用。

需要注意的是,Go语言的接口和嵌入机制并不完全等同于其他编程语言中的trait。它们只是提供了一种实现类似功能的方式,以满足特定的编程需求。

Go语言教程之边写边学:Golang Web服务器示例

Web服务器的主要功能是:

  1. 侦听来自客户端(如Web浏览器或其他应用程序)的传入HTTP请求。
  2. 通过解释请求的资源(如网页或图像)和客户端发送的任何其他数据来处理这些请求。
  3. 以HTTP响应的形式将请求的内容或错误消息发送回客户端,该响应通常包括标头(元数据)和正文(实际内容)。

 

示例代码:

package main

import (
	"fmt"
	"net/http"
)

func hello(w http.ResponseWriter, _ *http.Request) {
	fmt.Fprintf(w, "Hello")
}

func main() {
	http.HandleFunc("/", hello)
	http.ListenAndServe("0.0.0.0:8080", nil)
}

您在Go中提供的最小Web服务器会侦听传入的HTTP请求,并在收到请求时以"Hello"进行响应。以下是收到请求时发生的情况的分步说明:

  1. 通过调用main函数来启动Web服务器。
  2. 在main中,服务器使用http将一个名为hello的函数注册为根路径("/")的处理程序。HandleFunc("/", hello)。这意味着当收到带有根路径的HTTP请求时,将调用hello函数来处理它。
  3. 服务器开始使用http在所有可用的网络接口0.0.0.0和端口8080上侦听传入的HTTP请求。ListenAndServe("0.0.0.0:8080",nil)。
  4. 收到请求后,服务器会检查请求的路径。由于根路径("/")已注册到hello函数,因此服务器调用hello函数来处理请求。
  5. hello函数有两个参数:w http。ResponseWriter和_ *http.请求。下划线(_)用于忽略第二个参数(请求),因为此示例中未使用它。
  6. 在hello函数中,服务器使用fmt将"Hello"写入响应。Fprintf(w,"hello")。http.ResponseWriter是一个接口,允许服务器构造HTTP响应和fmt.Fprintf将格式化的字符串"Hello"写入其中。
  7. 然后,响应被发送回客户端,客户端接收"Hello"消息。
  8. 总之,当服务器收到请求时,它会调用hello函数,将"Hello"写入响应,并将其发送回客户端。

 

解释Go Web服务器进行的所有系统调用

要捕获和解释在Linux上运行的Go Web服务器进行的所有系统调用,您可以使用像strace这样的工具。但是,提供系统调用及其解释的详尽列表超出了本答案的范围。相反,我将解释一些关键系统调用,这些调用可能会在运行提供的Go Web服务器时观察到。

socket():此系统调用为服务器创建一个新的网络套接字。它用于为服务器创建通信终结点,以侦听传入连接。
bind():此系统调用将socket()创建的套接字绑定到特定地址和端口(在本例中为"0.0.0.0:8080")。这允许服务器侦听指定地址和端口上的传入连接。
listen():此系统调用将套接字标记为被动套接字,该套接字将用于通过accept()系统调用接受传入的连接请求。它还指定挂起连接队列的最大长度。
accept():此系统调用用于接受来自客户端的传入连接请求。当客户端连接到服务器时,accept()调用将返回一个新的套接字文件描述符,该描述符表示与该特定客户端的连接。这允许服务器同时处理多个客户端。
epoll_create1()、epoll_ctl()、epoll_wait():这些系统调用用于高效的I/O多路复用。它们允许服务器监视多个文件描述符(套接字)的各种I/O事件(例如传入数据或写入准备),而不必单独阻止每个事件。这对于服务器的性能非常重要,尤其是在处理大量客户端时。
read()、write():这些系统调用用于读取来自客户端的传入HTTP请求并将响应写回客户端。在提供的Web服务器中,当服务器将"Hello"写入http时,这些调用发生在hello()函数中。响应编写器。
close():此系统调用用于在请求处理完成后关闭与客户端的连接。


请注意,这并不是Go Web服务器可能进行的系统调用的详尽列表,但它涵盖了设置和处理连接的最重要的调用。实际进行的系统调用可能因Go标准库和底层Linux内核的具体实现而异。

Go语言教程之边写边学:Golang中的字符串:字符串字符编码

字符串通过字符编码在计算机中存储和表示。在Go中,字符串默认使用UTF-8编码,这意味着它可以轻松表示任何Unicode字符。

什么是字符编码?

字符编码是一组将字符转换为计算机可以理解的数字代码的规则。常见的字符编码包括ASCII、ISO-8859-1和UTF-8。

UTF-8编码简介

UTF-8是一种可变长度的Unicode字符编码方法,它使用1到4个字节来表示字符。它是Unicode标准的官方推荐编码。

 

示例代码:

当你运行这个时,你会看到像Go (ASCII)这样的字符由单个字节表示,而 (Unicode) 在其UTF-8编码中由多个字节表示。

package main

import (
  "fmt"
)

func main() {
  // 包含ASCII和Unicode字符str := "Go世界"

  fmt.Println("String:", str)

  // 输出unicode编码fmt.Println("Rune Code Points:")
  for _, runeValue := range str {
    fmt.Printf("%c: %U\n", runeValue, runeValue)
  }

  // 输出UTF-8编码byte
  fmt.Println("UTF-8 Bytes:")
  for i := 0; i < len(str); i++ {
    fmt.Printf("%c: %x\n", str[i], str[i])
  }
}

输出:

Rune Code Points:
G: U+0047
o: U+006F世: U+4E16界: U+754C

UTF-8 Bytes:
G: 47
o: 6f
ä: e4
¸: b8
–: 96
ç: e7
•: 95
Œ: 8c

 

Unicode码位和符文类型

Unicode码位是每个字符的唯一数字表示形式。在Go中,可以使用类型存储和处理符文Unicode码位。

示例代码:

当您运行该程序时,它将打印字符串语言中字符的Unicode码位。

package main

import (
  "fmt"
)

func main() {
  str := "语言"

  for _, char := range str {
    fmt.Printf("U+%04X ", char) // U+8BED U+8A00
  }
}

 

字符串与UTF-8的互操作性

可以使用len函数获取字符串的字节长度,但在UTF-8编码下,需要用utf8.RuneCountInString来获取字符数

str := "语言"
byteLen := len(str)
runeLen := utf8.RuneCountInString(str)
fmt.Println(byteLen)  // 6
fmt.Println(runeLen)  // 2

 

将字符串解码为符文切片

使用[]rune将字符串转换为符文切片。

str := "语言"
runes := []rune(str)
fmt.Println(runes) // [35821 35328]

 

转换字符编码

尽管Go主要支持UTF-8,但有时可能需要与其他字符编码(如ISO-8859-1或GBK)进行互操作。在这种情况下,可以使用第三方库,例如golang.org/x/text/encoding

import "golang.org/x/text/encoding/simplifiedchinese"
import "golang.org/x/text/transform"

str := "语言"
encoder := simplifiedchinese.GB18030.NewEncoder()
encoded, _, _ := transform.String(encoder, str)
fmt.Println(encoded) // ����

 

Go语言教程之边写边学:Golang中的字符串:字符串操作

字符串连接

在Go中,可以使用运算符连接两个或多个字符串。

示例代码:

str1 := "Hello, "
str2 := "world!"
result := str1 + str2
fmt.Println(result) // Hello, world!

 

字符串切片

由于Go字符串是它们后面的字节切片,因此您可以像数组或切片一样处理字符串以获取字符串的子字符串。

示例代码:

str := "Hello, World!"
// 从下标7开始到11,不包含12
substring := str[7:12]
fmt.Println(substring) // Outputs: "World"

 

字符串搜索

您可以使用包中的字符串函数(如 Contains 等)轻松查找子字符串或字符。

示例代码:

package main

import (
  "fmt"
  "strings"
)

func main() {
  haystack := "Hello, Golang World!"


  needle := "Golang"


  if strings.Contains(haystack, needle) {
    fmt.Println("Found:", needle)
  } else {
    fmt.Println(needle, "not found!")
  }
}

 

字符串比较

Go提供了一种比较两个字符串是否相等的原生方法。此外,库Compare 中的函数字符串可用于确定两个字符串的字典顺序。

package main

import (
  "fmt"
)

func main() {
  str1 := "hello"
  str2 := "world"
  str3 := "hello"


  if str1 == str2 {
    fmt.Println("str1 and str2 are equal.")
  } else {
    fmt.Println("str1 and str2 are not equal.")
  }

  if str1 == str3 {
    fmt.Println("str1 and str3 are equal.")
  } else {
    fmt.Println("str1 and str3 are not equal.")
  }
}

输出:

str1 and str2 are not equal.
str1 and str3 are equal.

 

字符串替换

使用 ReplaceReplaceAll 函数,可以在Go中替换字符串中的子字符串。

package main

import (
  "fmt"
  "strings"
)

func main() {
  s := "banana"
  
  // 替换前两个'a' 和 'o'
  r1 := strings.Replace(s, "a", "o", 2)
  fmt.Println(r1) // "bonona"

  // 替换所有'a'和'o'
  r2 := strings.ReplaceAll(s, "a", "o")
  fmt.Println(r2) // "bonono"
}

 

字符串大小写转换

Go字符串库提供用于大小写转换的 ToUpperToLower 函数。

str := "GoLang"
lowercase := strings.ToLower(str)
uppercase := strings.ToUpper(str)
fmt.Println(lowercase)
fmt.Println(uppercase)

 

使用正则表达式处理字符串

Go正表达式库提供了一系列函数来使用正则表达式查询、匹配、替换和拆分字符串。

import "regexp"

str := "My email is example@example.com"
re := regexp.MustCompile(`[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,4}`)
email := re.FindString(str)
fmt.Println(email) // example@example.com

 

字符串加密和哈希

Go的加密包提供了多种加密算法,可用于加密字符串或计算字符串的哈希值。

import (
    "crypto/md5"
    "fmt"
    "io"
)

str := "secret data"
hasher := md5.New()
io.WriteString(hasher, str)
fmt.Printf("%x\n", hasher.Sum(nil))

 

字符串拆分

使用字符串。拆分函数,可以通过指定的分隔符将字符串拆分为子字符串的切片。

str := "apple,banana,cherry"
items := strings.Split(str, ",")
fmt.Println(items)

 

字符串合并

字符串。Join 函数,将字符串切片组合成一个字符串。

items := []string{"apple", "banana", "cherry"}
str := strings.Join(items, ", ")
fmt.Println(str)

 

获取字符串中的字符

字符串中的每个字符都可以通过索引访问,但返回字符的字节值。

str := "Go"
byteValue := str[1]
fmt.Println(byteValue)

 

遍历字符串中的字符

使用for range 循环遍历字符串中的每个字符。

str := "Go"
for index, char := range str {
    fmt.Printf("At index %d, char: %c\n", index, char)
}

// At index 0, char: G
// At index 1, char: o

 

修剪字符串

字符串。TrimSpace 该函数可以删除字符串开头和结尾的空格。

str := "   Go Lang   "
trimmed := strings.TrimSpace(str)
fmt.Println(trimmed)

 

填充字符串

使用fmt包,您可以使用特定的格式修饰符填充或对齐字符串。

str := "Go"
padded := fmt.Sprintf("%-10s", str)
fmt.Println(padded)

 

字符串统计信息

count该函数可以帮助计算子字符串在字符串中出现的次数。

str := "Go is easy to learn. Go is powerful."
count := strings.Count(str, "Go")
fmt.Println(count)
Go语言教程之边写边学:Golang中的字符串

在现代编程中,字符串处理是一个不可或缺的部分。无论是简单的用户界面还是复杂的数据处理,字符串都起着关键作用。Go语言作为一种现代的高性能编程语言,为字符串处理提供了一系列强大的工具和函数。

字符串在编程世界中至关重要,无论您是处理用户输入还是从数据库中读取数据,都离不开它们。Go语言为字符串处理提供了简单高效的工具。

 

字符串的定义和特征

在Go中,字符串是字节的任意集合,通常用于表示文本。字符串是不可变的,这意味着您不能修改字符串的字符,但可以生成新字符串。

greeting := "Hello, Go!"
fmt.Println(greeting)

 

Go字符串不可变性原则

在Go中创建的每个字符串都是不可变的。这意味着您不能直接修改字符串中的字符。这种设计可以为字符串操作带来一些性能优势,尤其是在复制和传递字符串时。

package main

import "fmt"

func main() {
    original := "hello"
    modified := original

    modified = "world"

    fmt.Println(original)  // Outputs: hello
    fmt.Println(modified)  // Outputs: world
}

在此示例中,即使我们将original分配给modified,更改modified也不会影响original。
这是因为Go中的字符串是不可变的,并且对modified的更改会在内存中创建一个新字符串,而不是更改现有字符串。

 

Go字符串的内部表示

Go字符串后面是一个字节数组,这也意味着Go可以存储任何数据,而不仅仅是UTF-8文本。

s := "hello"

在内部,这可以表示为: - 字节数组:
[104, 101, 108, 108, 111] (分别是字母h、e、l、l、o的ASCII值)
- 指向此数组开头的指针。
- 长度为5,表示字符串中有5个字节。

Go语言教程之边写边学:golang中捕获panic

Golang官方包使用panic/defer+recover作为throw/catch,但只有在需要展开大型调用堆栈时才会使用。"惯用"的解决方案是在使用参数之前检查参数。
当程序崩溃时,当前函数将停止运行,并且程序会打印日志消息并崩溃。
您只需调用内置的panic函数即可自行引起恐慌。

示例代码:

package main

import (
	"errors"
	"fmt"
)

var result = 1

func chain(n int) {
	defer func() {
		if r := recover(); r != nil {
			fmt.Println(r)
		}
	}()

	if n == 0 {
		panic(errors.New("Cannot multiply a number by zero"))
	} else {
		result *= n
		fmt.Println("Output: ", result)
	}
}

func main() {
	chain(5)
	chain(2)
	chain(0)
	chain(8)
}
Go语言教程之边写边学:golang中创建结构体字典

示例代码:

package main

import "fmt"

type Emp struct {
	x int
	y []string
}

func main() {
	var list = map[string]*Emp{"e1": {1001, []string{"John", "US"}}}

	e := new(Emp)
	e.x = 1002
	e.y = []string{"Rock", "UK"}

	list["e2"] = e

	fmt.Println(list["e1"])
	fmt.Println(list["e2"])
}

 

输出:

&{1001 [John US]}
&{1002 [Rock UK]}
Go语言教程之边写边学:golang中创建结构体切片

示例代码:

package main

import (
	"fmt"
)

type Widget struct {
	id    int
	attrs []string
}

func main() {

	widgets := []Widget{
		Widget{
			id:    10,
			attrs: []string{"blah", "foo"},
		},
		Widget{
			id:    11,
			attrs: []string{"foo", "bar"},
		},
		Widget{
			id:    12,
			attrs: []string{"xyz"},
		},
	}

	for _, j := range widgets {
		fmt.Printf("%d ", j.id)
		for _, y := range j.attrs {
			fmt.Printf(" %s ", y)
		}
		fmt.Println()
	}
}

输出:

10  blah  foo 
11  foo  bar
12  xyz
Go语言教程之边写边学:Golang中的反射:Reflect包的Make相关函数

MakeSlice函数为指定的切片类型、长度和容量创建一个新的零初始化切片值。

示例代码:

package main

import (
	"fmt"
	"reflect"
)

func main() {
	var str []string
	var strType reflect.Value = reflect.ValueOf(&str)
	newSlice := reflect.MakeSlice(reflect.Indirect(strType).Type(), 10, 15)

	fmt.Println("Kind :", newSlice.Kind())
	fmt.Println("Length :", newSlice.Len())
	fmt.Println("Capacity :", newSlice.Cap())
}

输出:

Kind : slice
Length : 10
Capacity : 15

 

MakeMap将创建一个具有指定类型的新映射。

示例代码:

package main

import (
	"fmt"
	"reflect"
)

func main() {
	var str map[string]string
	var strType reflect.Value = reflect.ValueOf(&str)
	newMap := reflect.MakeMap(reflect.Indirect(strType).Type())

	fmt.Println("Kind :", newMap.Kind())
}

输出:

Kind : map

 

MakeChan创建一个具有指定类型和缓冲区大小的新通道。

示例代码:

package main

import (
	"fmt"
	"reflect"
)

func main() {
	var str chan string
	var strType reflect.Value = reflect.ValueOf(&str)
	newChannel := reflect.MakeChan(reflect.Indirect(strType).Type(), 512)

	fmt.Println("Kind :", newChannel.Kind())
	fmt.Println("Capacity :", newChannel.Cap())
}

输出:

Kind : chan
Capacity : 512

 

MakeFunc函数用于获取包装函数fn的给定Type的新函数。

示例代码:

package main

import (
	"fmt"
	"reflect"
)

type Sum func(int64, int64) int64

func main() {
	t := reflect.TypeOf(Sum(nil))
	mul := reflect.MakeFunc(t, func(args []reflect.Value) []reflect.Value {
		a := args[0].Int()
		b := args[1].Int()
		return []reflect.Value{reflect.ValueOf(a + b)}
	})
	fn, ok := mul.Interface().(Sum)
	if !ok {
		return
	}
	fmt.Println(fn(5, 6))
}

输出:

11
Go语言教程之边写边学:Golang中的反射:Reflect包的Field相关函数

NumField函数

返回给定结构中的字段数。

 

示例代码:

package main

import (
	"fmt"
	"reflect"
)

type T struct {
	A int
	B string
	C float64
	D bool
}

func main() {
	t := T{10, "ABCD", 15.20, true}
	typeT := reflect.TypeOf(t)
	fmt.Println(typeT.NumField()) // 4
}

 

field函数

Field函数用于访问结构字段的名称和类型。

示例代码:

package main

import (
	"fmt"
	"reflect"
)

type T struct {
	A int
	B string
	C float64
	D bool
}

func main() {
	t := T{10, "ABCD", 15.20, true}
	typeT := reflect.TypeOf(t)

	for i := 0; i < typeT.NumField(); i++ {
		field := typeT.Field(i)
		fmt.Println(field.Name, field.Type)
	}
}

输出:

A int
B string 
C float64
D bool

 

FieldByIndex函数

FieldByIndex函数用于获取index对应的嵌套字段

package main

import (
	"fmt"
	"reflect"
)

type First struct {
	A int
	B string
	C float64
}

type Second struct {
	First
	D bool
}

func main() {
	s := Second{First: First{10, "ABCD", 15.20}, D: true}
	t := reflect.TypeOf(s)

	fmt.Printf("%#v\n", t.FieldByIndex([]int{0}))
	fmt.Printf("%#v\n", t.FieldByIndex([]int{0, 0}))
	fmt.Printf("%#v\n", t.FieldByIndex([]int{0, 1}))
	fmt.Printf("%#v\n", t.FieldByIndex([]int{0, 2}))
	fmt.Printf("%#v\n", t.FieldByIndex([]int{1}))
}

输出:

reflect.StructField{Name:"First", PkgPath:"", Type:(*reflect.rtype)(0x4bda40), Tag:"", Offset:0x0, Index:[]int{0}, Anonymous:true}
reflect.StructField{Name:"A", PkgPath:"", Type:(*reflect.rtype)(0x4ad800), Tag:"", Offset:0x0, Index:[]int{0}, Anonymous:false} 
reflect.StructField{Name:"B", PkgPath:"", Type:(*reflect.rtype)(0x4adf80), Tag:"", Offset:0x8, Index:[]int{1}, Anonymous:false} 
reflect.StructField{Name:"C", PkgPath:"", Type:(*reflect.rtype)(0x4ad400), Tag:"", Offset:0x18, Index:[]int{2}, Anonymous:false}
reflect.StructField{Name:"D", PkgPath:"", Type:(*reflect.rtype)(0x4ad200), Tag:"", Offset:0x20, Index:[]int{1}, Anonymous:false

 

FieldByName函数

FieldByName函数用于通过给定的字段名称获取和设置结构字段值。

示例代码:

package main

import (
	"fmt"
	"reflect"
)

type T struct {
	A int
	B string
	C float64
}

func main() {
	s := T{10, "ABCD", 15.20}
	fmt.Println(reflect.ValueOf(&s).Elem().FieldByName("A"))
	fmt.Println(reflect.ValueOf(&s).Elem().FieldByName("B"))
	fmt.Println(reflect.ValueOf(&s).Elem().FieldByName("C"))

	reflect.ValueOf(&s).Elem().FieldByName("A").SetInt(50)
	reflect.ValueOf(&s).Elem().FieldByName("B").SetString("Test")
	reflect.ValueOf(&s).Elem().FieldByName("C").SetFloat(5.5)

	fmt.Println(reflect.ValueOf(&s).Elem().FieldByName("A"))
	fmt.Println(reflect.ValueOf(&s).Elem().FieldByName("B"))
	fmt.Println(reflect.ValueOf(&s).Elem().FieldByName("C"))
}

输出:

10
ABCD
15.2
50  
Test
5.5
Go语言教程之边写边学:Golang中的反射:Reflect包的ValueOf函数

ValueOf函数来创建一个reflect。表示变量值的Value实例。

 

示例代码:

package main

import (
	"fmt"
	"reflect"
)

func main() {
	v1 := []int{1, 2, 3, 4, 5}
	fmt.Println(reflect.ValueOf(v1))

	v2 := "Hello World"
	fmt.Println(reflect.ValueOf(v2))

	v3 := 1000
	fmt.Println(reflect.ValueOf(v3))
	fmt.Println(reflect.ValueOf(&v3))

	v4 := map[string]int{"mobile": 10, "laptop": 5}
	fmt.Println(reflect.ValueOf(v4))

	v5 := [5]int{1, 2, 3, 4, 5}
	fmt.Println(reflect.ValueOf(v5))

	v6 := true
	fmt.Println(reflect.ValueOf(v6))
}

 

输出:

[1 2 3 4 5]
Hello World
1000
0xc0000a00b8
map[laptop:5 mobile:10]
[1 2 3 4 5]
true
Go语言教程之边写边学:Golang中的反射:Reflect包的TypeOf函数

TypeOf函数返回reflect类型的值,即传递给TypeOf函数的变量的类型。

示例代码:

package main

import (
	"fmt"
	"reflect"
)

func main() {
	v1 := []int{1, 2, 3, 4, 5}
	fmt.Println(reflect.TypeOf(v1))

	v2 := "Hello World"
	fmt.Println(reflect.TypeOf(v2))

	v3 := 1000
	fmt.Println(reflect.TypeOf(v3))

	v4 := map[string]int{"mobile": 10, "laptop": 5}
	fmt.Println(reflect.TypeOf(v4))

	v5 := [5]int{1, 2, 3, 4, 5}
	fmt.Println(reflect.TypeOf(v5))

	v6 := true
	fmt.Println(reflect.TypeOf(v6))
}

 

输出:

[]int
string        
int
map[string]int
[5]int        
bool
Go语言教程之边写边学:Golang中的反射:Reflect包的swapper函数

Swapper函数用于交换所提供切片中的元素。您也可以以巧妙的方式使用此功能来反转或排序切片。

示例代码:

package main

import (
	"fmt"
	"reflect"
)

func main() {
	theList := []int{1, 2, 3, 4, 5}
	swap := reflect.Swapper(theList)
	fmt.Printf("Original Slice :%v\n", theList)

	// 按下标交换元素swap(1, 3)
	fmt.Printf("After Swap :%v\n", theList)

	// 反转slice元素for i := 0; i < len(theList)/2; i++ {
		swap(i, len(theList)-1-i)
	}
	fmt.Printf("After Reverse :%v\n", theList)
}

输出:

Original Slice :[1 2 3 4 5]
After  Swap :[1 4 3 2 5]
After Reverse :[5 2 3 4 1]
Go语言教程之边写边学:Golang中的反射:Reflect包的DeepEqual函数

无论x和y是否"深度相等",DeepEqual都返回True或False。当数组值的相应元素深度相等时,数组值深度相等。如果结构值的对应字段(导出和未导出)非常相等,则它们非常相等。切片值在以下情况下非常相等(它们都是nil或都是非nil,它们具有相同的长度,并且它们指向同一基础数组的相同初始条目)。

示例代码:

package main

import (
	"fmt"
	"reflect"
)

type mobile struct {
	price float64
	color string
}

func main() {
	// DeepEqual is used to check two slices are equal or not
	s1 := []string{"A", "B", "C", "D", "E"}
	s2 := []string{"D", "E", "F"}
	result := reflect.DeepEqual(s1, s2)
	fmt.Println(result)

	// DeepEqual is used to check two arrays are equal or not
	n1 := [5]int{1, 2, 3, 4, 5}
	n2 := [5]int{1, 2, 3, 4, 5}
	result = reflect.DeepEqual(n1, n2)
	fmt.Println(result)

	// DeepEqual is used to check two structures are equal or not
	m1 := mobile{500.50, "red"}
	m2 := mobile{400.50, "black"}
	result = reflect.DeepEqual(m1, m2)
	fmt.Println(result)
}

 

输出:

false
true 
false
Go语言教程之边写边学:Golang中的反射:Reflect 包的copy函数

Go中的反射是元编程的一种形式。反射允许我们在运行时检查类型。它还提供了在运行时检查、修改和创建变量、函数和结构的功能。Go reflect包为您提供了在运行时检查和操作对象的功能。对于开发人员来说,反射是一个非常强大的工具,它扩展了任何编程语言的视野。类型、种类和值是用于查找信息的三个重要反射部分。

copy函数将源的内容复制到目标中,直到目标被填满或源已用尽。它返回复制的元素数。目标和源必须具有Slice或Array类型,并且目标和源必须具有相同的元素类型。

 

示例代码:

package main

import (
	"fmt"
	"reflect"
)

func main() {
	destination := reflect.ValueOf([]string{"A", "B", "C"})
	source := reflect.ValueOf([]string{"D", "E", "F"})

	// Copy() function is used and it returns the number of elements copied
	counter := reflect.Copy(destination, source)
	fmt.Println(counter)

	fmt.Println(source)
	fmt.Println(destination)
}

 

输出:

3
[D E F]
[D E F]

 

Go语言教程之边写边学:常用的软件库:Golang统计包

此软件包提供用于计算数值数据的数理统计的函数。即使数据集太大,也可以使用它。此包不能依赖于导入其他模块、包或库。您可以获得常用的统计函数,如平均值、中位数、标准差、方差、相关性、谐波平均值等。

安装软件包:

go get github.com/montanaflynn/stats

 

示例代码:

package main

import (
	"fmt"

	"github.com/montanaflynn/stats"
)

func main() {

	// d := stats.LoadRawData([]interface{}{1.1, "2", 3.0, 4, "5"})
	d := stats.LoadRawData([]int{1, 2, 3, 4, 5})

	a, _ := stats.Min(d)
	fmt.Println(a)
	// Output: 1.1

	a, _ = stats.Max(d)
	fmt.Println(a)
	// Output: 5

	a, _ = stats.Sum([]float64{1.1, 2.2, 3.3})
	fmt.Println(a)
	// Output: 6.6

	cs, _ := stats.CumulativeSum([]float64{1.1, 2.2, 3.3})
	fmt.Println(cs) // [1.1 3.3000000000000003 6.6]

	a, _ = stats.Mean([]float64{1, 2, 3, 4, 5})
	fmt.Println(a)
	// Output: 3

	a, _ = stats.Median([]float64{1, 2, 3, 4, 5, 6, 7})
	fmt.Println(a)
	// Output: 4

	m, _ := stats.Mode([]float64{5, 5, 3, 3, 4, 2, 1})
	fmt.Println(m)
	// Output: [5 3]

	a, _ = stats.PopulationVariance([]float64{1, 2, 3, 4, 5})
	fmt.Println(a)
	// Output: 2

	a, _ = stats.SampleVariance([]float64{1, 2, 3, 4, 5})
	fmt.Println(a)
	// Output: 2.5

	a, _ = stats.MedianAbsoluteDeviationPopulation([]float64{1, 2, 3})
	fmt.Println(a)
	// Output: 1

	a, _ = stats.StandardDeviationPopulation([]float64{1, 2, 3})
	fmt.Println(a)
	// Output: 0.816496580927726

	a, _ = stats.StandardDeviationSample([]float64{1, 2, 3})
	fmt.Println(a)
	// Output: 1

	a, _ = stats.Percentile([]float64{1, 2, 3, 4, 5}, 75)
	fmt.Println(a)
	// Output: 4

	a, _ = stats.PercentileNearestRank([]float64{35, 20, 15, 40, 50}, 75)
	fmt.Println(a)
	// Output: 40

	c := []stats.Coordinate{
		{1, 2.3},
		{2, 3.3},
		{3, 3.7},
		{4, 4.3},
		{5, 5.3},
	}

	r, _ := stats.LinearRegression(c)
	fmt.Println(r)
	// Output: [{1 2.3800000000000026} {2 3.0800000000000014} {3 3.7800000000000002} {4 4.479999999999999} {5 5.179999999999998}]

	r, _ = stats.ExponentialRegression(c)
	fmt.Println(r)
	// Output: [{1 2.5150181024736638} {2 3.032084111136781} {3 3.6554544271334493} {4 4.406984298281804} {5 5.313022222665875}]

	r, _ = stats.LogarithmicRegression(c)
	fmt.Println(r)
	// Output: [{1 2.1520822363811702} {2 3.3305559222492214} {3 4.019918836568674} {4 4.509029608117273} {5 4.888413396683663}]

	s, _ := stats.Sample([]float64{0.1, 0.2, 0.3, 0.4}, 3, false)
	fmt.Println(s)
	// Output: [0.2,0.4,0.3]

	s, _ = stats.Sample([]float64{0.1, 0.2, 0.3, 0.4}, 10, true)
	fmt.Println(s)
	// Output: [0.2,0.2,0.4,0.1,0.2,0.4,0.3,0.2,0.2,0.1]

	q, _ := stats.Quartile([]float64{7, 15, 36, 39, 40, 41})
	fmt.Println(q)
	// Output: {15 37.5 40}

	iqr, _ := stats.InterQuartileRange([]float64{102, 104, 105, 107, 108, 109, 110, 112, 115, 116, 118})
	fmt.Println(iqr)
	// Output: 10

	mh, _ := stats.Midhinge([]float64{1, 3, 4, 4, 6, 6, 6, 6, 7, 7, 7, 8, 8, 9, 9, 10, 11, 12, 13})
	fmt.Println(mh)
	// Output: 7.5

	tr, _ := stats.Trimean([]float64{1, 3, 4, 4, 6, 6, 6, 6, 7, 7, 7, 8, 8, 9, 9, 10, 11, 12, 13})
	fmt.Println(tr)
	// Output: 7.25

	o, _ := stats.QuartileOutliers([]float64{-1000, 1, 3, 4, 4, 6, 6, 6, 6, 7, 8, 15, 18, 100})
	fmt.Printf("%+v\n", o)
	// Output:  {Mild:[15 18] Extreme:[-1000 100]}

	gm, _ := stats.GeometricMean([]float64{10, 51.2, 8})
	fmt.Println(gm)
	// Output: 15.999999999999991

	hm, _ := stats.HarmonicMean([]float64{1, 2, 3, 4, 5})
	fmt.Println(hm)
	// Output: 2.18978102189781

	a, _ = stats.Round(2.18978102189781, 3)
	fmt.Println(a)
	// Output: 2.189

	e, _ := stats.ChebyshevDistance([]float64{2, 3, 4, 5, 6, 7, 8}, []float64{8, 7, 6, 5, 4, 3, 2})
	fmt.Println(e)
	// Output: 6

	e, _ = stats.ManhattanDistance([]float64{2, 3, 4, 5, 6, 7, 8}, []float64{8, 7, 6, 5, 4, 3, 2})
	fmt.Println(e)
	// Output: 24

	e, _ = stats.EuclideanDistance([]float64{2, 3, 4, 5, 6, 7, 8}, []float64{8, 7, 6, 5, 4, 3, 2})
	fmt.Println(e)
	// Output: 10.583005244258363

	e, _ = stats.MinkowskiDistance([]float64{2, 3, 4, 5, 6, 7, 8}, []float64{8, 7, 6, 5, 4, 3, 2}, float64(1))
	fmt.Println(e)
	// Output: 24

	e, _ = stats.MinkowskiDistance([]float64{2, 3, 4, 5, 6, 7, 8}, []float64{8, 7, 6, 5, 4, 3, 2}, float64(2))
	fmt.Println(e)
	// Output: 10.583005244258363

	e, _ = stats.MinkowskiDistance([]float64{2, 3, 4, 5, 6, 7, 8}, []float64{8, 7, 6, 5, 4, 3, 2}, float64(99))
	fmt.Println(e)
	// Output: 6

	cor, _ := stats.Correlation([]float64{1, 2, 3, 4, 5}, []float64{1, 2, 3, 5, 6})
	fmt.Println(cor)
	// Output: 0.9912407071619302

	ac, _ := stats.AutoCorrelation([]float64{1, 2, 3, 4, 5}, 1)
	fmt.Println(ac)
	// Output: 0.4

	sig, _ := stats.Sigmoid([]float64{3.0, 1.0, 2.1})
	fmt.Println(sig)
	// Output: [0.9525741268224334 0.7310585786300049 0.8909031788043871]

	sm, _ := stats.SoftMax([]float64{3.0, 1.0, 0.2})
	fmt.Println(sm)
	// Output: [0.8360188027814407 0.11314284146556013 0.05083835575299916]

	e, _ = stats.Entropy([]float64{1.1, 2.2, 3.3})
	fmt.Println(e)
	// Output: 1.0114042647073518
}
Go语言教程之边写边学:常用的软件库:Golang中的动态JSON

Gabs是一个小型实用程序,用于处理Go中的动态或未知JSON结构。它不需要您知道有效负载的结构(例如创建结构),并允许通过提供字段的路径来访问字段。它是一个有用的包装器,用于访问encoding/json包提供的map[string]interface{} 对象的层次结构。

安装软件包:

go get github.com/Jeffail/gabs

 

示例代码:

package main

import (
	"fmt"

	"github.com/Jeffail/gabs"
)

func main() {
	data := []byte(`{
		"employees":{
		   "protected":false,
		   "address":{
			  "street":"22 Saint-Lazare",
			  "postalCode":"75003",
			  "city":"Paris",
			  "countryCode":"FRA",
			  "country":"France"
		   },
		   "employee":[
			  {
				 "id":1,
				 "first_name":"Jeanette",
				 "last_name":"Penddreth"
			  },
			  {
				 "id":2,
				 "firstName":"Giavani",
				 "lastName":"Frediani"
			  }
		   ]
		}
	 }`)

	jsonParsed, err := gabs.ParseJSON(data)
	if err != nil {
		panic(err)
	}

	// Search JSON
	fmt.Println("Get value of Protected:\t", jsonParsed.Path("employees.protected").Data())
	fmt.Println("Get value of Country:\t", jsonParsed.Search("employees", "address", "country").Data())
	fmt.Println("ID of first employee:\t", jsonParsed.Path("employees.employee.0.id").String())
	fmt.Println("Check Country Exists:\t", jsonParsed.Exists("employees", "address", "countryCode"))

	// Iterating address objects
	for key, child := range jsonParsed.Search("employees", "address").ChildrenMap() {
		fmt.Printf("Key=>%v, Value=>%v\n", key, child.Data().(string))
	}

	// Iterating employee array
	for _, child := range jsonParsed.Search("employees", "employee").Children() {
		fmt.Println(child.Data())
	}

	// Use index in your search
	for _, child := range jsonParsed.Search("employees", "employee", "0").Children() {
		fmt.Println(child.Data())
	}
}

输出:

Get value of Protected:  false
Get value of Country:    France
ID of first employee:    1
Check Country Exists:    true
Key=>street, Value=>22 Saint-Lazare
Key=>postalCode, Value=>75003
Key=>city, Value=>Paris
Key=>countryCode, Value=>FRA
Key=>country, Value=>France
map[id:1 first_name:Jeanette last_name:Penddreth]
map[id:2 firstName:Giavani lastName:Frediani]
Jeanette
Penddreth1
  • 当前日期:
  • 北京时间:
  • 时间戳:
  • 今年的第:17周
  • 我的 IP:3.149.241.32
农历
五行
冲煞
彭祖
方位
吉神
凶神
极简任务管理 help
+ 0 0 0
Task Idea Collect