通过示例学习-Go-语言-2023-二十八-
通过示例学习 Go 语言 2023(二十八)
在 Go(Golang)中逐行读取大文件
来源:
golangbyexample.com/read-large-file-line-by-line-go/
当涉及到读取大文件时,显然我们不想将整个文件加载到内存中。Golang 中的 bufio 包在读取大文件时提供了帮助。假设我们有一个名为 sample.txt 的文件,其内容如下
This is an example
to show how
to read file
line by line.
这是程序:
package main
import (
"bufio"
"fmt"
"log"
"os"
)
func main(){
LinebyLineScan()
}
func LinebyLineScan() {
file, err := os.Open("./sample.txt")
if err != nil {
log.Fatal(err)
}
defer file.Close()
scanner := bufio.NewScanner(file)
for scanner.Scan() {
fmt.Println(scanner.Text())
}
if err := scanner.Err(); err != nil {
log.Fatal(err)
}
}
输出:
This is an example
to show how
to read file
line by line.
不过请注意,bufio.Scanner 的最大缓冲区大小为 641024 字节,这意味着如果你的文件中有任何一行超过 641024 的大小,那么它将会报错
bufio.Scanner: token too long
- 文件* go* 大文件* 逐行读取* 逐行
在 Go(Golang)中逐字读取大型文件
来源:
golangbyexample.com/read-large-file-word-by-word-go/
处理大型文件时,显然我们不想将整个文件加载到内存中。在 Golang 中,bufio 包在读取大型文件时提供了帮助。假设我们有一个名为 sample.txt 的文件,内容如下:
This is an example
to show how
to read file
word by word.
逐字扫描
package main
import (
"bufio"
"fmt"
"log"
"os"
)
func main() {
WordbyWordScan()
}
func WordbyWordScan() {
file, err := os.Open("./scanner/sample.txt")
if err != nil {
log.Fatal(err)
}
defer file.Close()
scanner := bufio.NewScanner(file)
scanner.Split(bufio.ScanWords)
for scanner.Scan() {
fmt.Println(scanner.Text())
}
if err := scanner.Err(); err != nil {
log.Fatal(err)
}
}
输出:
This
is
an
example
to
show
how
to
read
file
line
by
line
and
word
by
word.
请注意,在上面的程序中,我们设置了scanner.Split(bufio.ScanWords),这有助于我们逐字读取文件。不过需要注意的是,bufio.Scanner 的最大缓冲区大小为 641024 字节,这意味着如果你的文件中有任何一行超过 641024 的大小,将会出现错误。
bufio.Scanner: token too long
在 Go(Golang)中读取 cookie http
来源:
golangbyexample.com/read-cookie-http-golang/
目录
-
概述
-
程序
概述
net/http Request 结构体提供了一种方便的方法,可以根据名称读取特定 cookie。以下是该方法的签名。golang.org/pkg/net/http/#Request.Cookie
func (r *Request) Cookie(name string) (*Cookie, error)
要打印所有 cookies,我们可以遍历http.Request结构体的Cookies方法。我们可以为此使用 range 关键字。
for _, c := range r.Cookies() {
fmt.Println(c)
}
这两个函数将返回Cookie结构体的实例。在 golang 中,cookie 表示如下。
golang.org/src/net/http/cookie.go
type Cookie struct {
Name string
Value string
Path string // optional
Domain string // optional
Expires time.Time // optional
RawExpires string // for reading cookies only
// MaxAge=0 means no 'Max-Age' attribute specified.
// MaxAge<0 means delete cookie now, equivalently 'Max-Age: 0'
// MaxAge>0 means Max-Age attribute present and given in seconds
MaxAge int
Secure bool
HttpOnly bool
SameSite SameSite
Raw string
Unparsed []string // Raw text of unparsed attribute-value pairs
}
有关上述 cookie 中每个字段的详细信息,请参见tools.ietf.org/html/rfc6265
。
程序
以下是相同程序,展示Cookie和Cookies方法的http.Request结构体
package main
import (
"fmt"
"log"
"net/http"
)
func main() {
docHandler := http.HandlerFunc(docHandler)
http.Handle("/doc", docHandler)
http.ListenAndServe(":8080", nil)
}
func docHandler(w http.ResponseWriter, r *http.Request) {
fmt.Println("Cookies in API Call:")
tokenCookie, err := r.Cookie("token")
if err != nil {
log.Fatalf("Error occured while reading cookie")
}
fmt.Println("\nPrinting cookie with name as token")
fmt.Println(tokenCookie)
fmt.Println("\nPrinting all cookies")
for _, c := range r.Cookies() {
fmt.Println(c)
}
fmt.Println()
w.WriteHeader(200)
w.Write([]byte("Doc Get Successful"))
return
}
运行上面的程序并进行以下 curl 调用
curl -X GET localhost:8080/doc --cookie "id=abcd; token=some_token"
curl 调用传递了两个 cookie 名称-值对
-
id=abcd
-
token=some_token
它将给出以下输出
Cookies in API Call:
Printing cookie with name as "token"
token=some_token
Printing all cookies
id=abcd
token=some_token
这就是我们如何打印名为“token”的特定 cookie
tokenCookie, err := r.Cookie("token")
它的输出如所见
token=some_token
这就是我们如何打印所有的 cookie
for _, c := range r.Cookies() {
fmt.Println(c)
}
它输出我们在 curl 调用中发送的 cookie 名称-值对
id=abcd
token=some_token
这就是关于 golang 中 cookies 的所有内容。希望你喜欢这个教程。请在评论中分享反馈。
此外,请查看我们的 Golang 高级教程系列 – Golang 高级教程
- cookie* go* golang*
在 Go (Golang) 中从通道读取/接收所有值
来源:
golangbyexample.com/receive-all-values-channel-golang/
目录
-
概述**
-
代码
概述
对于范围循环,可以用来接收来自通道的数据,直到它被关闭。请注意,for-range 循环会持续接收通道中的数据,唯一退出范围循环的方式是关闭通道。
让我们来看一个程序以理解这一点。
代码
package main
import (
"fmt"
"time"
)
func main() {
ch := make(chan int)
ch <- 2
ch <- 2
ch <- 2
close(ch)
sum(ch)
time.Sleep(time.Second * 1)
}
func sum(ch chan int) {
sum := 0
for val := range ch {
sum += val
}
fmt.Printf("Sum: %d\n", sum)
}
输出
Sum: 6
在上面的程序中,我们创建了一个通道。在主函数中,发送了三个值到通道,然后关闭了通道。接着我们调用了 sum 函数,并将通道传递给该函数。在 sum 函数中,我们对通道进行了 for-range 循环。在遍历完通道中的所有值后,由于通道已关闭,for-range 循环将退出。
现在脑海中浮现的问题是,如果在主函数中不关闭通道会发生什么。尝试注释掉关闭通道的那一行。然后运行程序。它也会输出死锁,因为 for-range 循环在 sum 函数中永远不会结束。
fatal error: all goroutines are asleep - deadlock!
如果我们需要在通道关闭前接收固定数量的值,可以使用 for 循环。让我们看一个例子。
package main
import (
"fmt"
"time"
)
func main() {
ch := make(chan int, 3)
ch <- 2
ch <- 2
ch <- 2
close(ch)
sum(ch)
time.Sleep(time.Second * 1)
}
func sum(ch chan int) {
sum := 0
for i := 0; i < 2; i++ {
val := <-ch
sum += val
}
fmt.Printf("Sum: %d\n", sum)
}
输出
Sum: 4
在上面的程序中,我们有一个容量为 3 的缓冲通道。在主函数中,我们向通道发送了 3 个值。在 sum 函数中,我们有一个 for 循环,迭代两次,只从通道中接收两个值并进行相加。只有在我们想从通道中接收固定数量的值时,for 循环才有用。
在 Go(Golang)中接收或获取来自 goroutine 的多个返回值
来源:
golangbyexample.com/receive-multiple-return-value-goroutine-golang/
通道可以用于从 goroutine 中获取返回值。通道提供了 goroutine 之间的同步和通信。你可以在 goroutine 中将返回值发送到通道,然后在主函数中收集该值。
为了接收多个值,我们可以创建一个自定义结构体类型,其中包含两个返回值的字段,然后创建该类型的通道。
让我们看看一个程序。
package main
import (
"fmt"
"time"
)
type result struct {
sumValue int
multiplyValue int
}
func main() {
resultChan := make(chan result, 1)
sumAndMultiply(2, 3, resultChan)
res := <-resultChan
fmt.Printf("Sum Value: %d\n", res.sumValue)
fmt.Printf("Multiply Value: %d\n", res.multiplyValue)
close(resultChan)
}
func sumAndMultiply(a, b int, resultChan chan result) {
sumValue := a + b
multiplyValue := a * b
res := result{sumValue: sumValue, multiplyValue: multiplyValue}
time.Sleep(time.Second * 2)
resultChan <- res
return
}
输出
Sum Value: 5
Multiply Value: 6
在上述程序中,我们创建了一个名为result的结构体,它有两个字段。
-
sumValue
-
multiplyValue
我们创建了一个变量resultChan,它是一个长度为 1 的通道,存储result结构体类型的值。我们将这个通道传递给sumAndMultiply函数。sumAndMultiply函数将结果结构体推送到resultChan。
res := result{sumValue: sumValue, multiplyValue: multiplyValue}
resultChan <- res
然后在主函数中,我们正在等待通道以收集结果。
res := <-resultChan
这行代码将等待,直到一个值被推送到resultChan通道。
从 Go(Golang)中的 goroutine 接收或获取返回值
来源:
golangbyexample.com/return-value-goroutine-go/
通道可以用来从 goroutine 获取返回值。通道提供了 goroutine 之间的同步和通信。你可以在 goroutine 中通过通道发送返回值,然后在 main 函数中收集该值。
让我们看看一个程序。
package main
import "fmt"
func main() {
result := make(chan int, 1)
go sum(2, 3, result)
value := <-result
fmt.Printf("Value: %d\n", value)
close(result)
}
func sum(a, b int, result chan int) {
sumValue := a + b
result <- sumValue
return
}
输出
Value: 5
在上面的程序中,我们创建了一个变量result,这是一个长度为 1、存放int类型值的通道。我们将这个通道传递给sum函数。sum函数将sumValue推送到result通道,如此操作。
result <- sumValue
在 main 函数中,我们在等待result通道以收集结果。
value := <-result
这一行将等待一个值被推送到result通道。如上所示,sumValue将通过sum函数推送到result通道。
为了说明这一行确实会等待,让我们在 sum 函数中设置一个超时,它实际上将sumValue推送到result通道。
package main
import (
"fmt"
"time"
)
func main() {
result := make(chan int, 1)
go sum(2, 3, result)
value := <-result
fmt.Printf("Value: %d\n", value)
close(result)
}
func sum(a, b int, result chan int) {
sumValue := a + b
time.Sleep(time.Second * 2)
result <- sumValue
return
}
输出
Value: 5
程序输出相同,这证明main函数等待sumValue被推送到result通道。一旦从result通道接收到值,它就会打印出来。
在 Go 语言中在不同函数中恢复 panic
来源:
golangbyexample.com/recover-panic-different-function-go/
目录
-
概述
-
程序
概述
如果defer函数和recover函数没有从引发恐慌的函数中被调用,那么在这种情况下panic也可以在被调用的函数中恢复。实际上,panic 可以在调用栈的后续链中恢复,让我们来看一个例子。
程序
package main
import "fmt"
func main() {
a := []string{"a", "b"}
checkAndPrintWithRecover(a, 2)
fmt.Println("Exiting normally")
}
func checkAndPrintWithRecover(a []string, index int) {
defer handleOutOfBounds()
checkAndPrint(a, 2)
}
func checkAndPrint(a []string, index int) {
if index > (len(a) - 1) {
panic("Out of bound access for slice")
}
fmt.Println(a[index])
}
func handleOutOfBounds() {
if r := recover(); r != nil {
fmt.Println("Recovering from panic:", r)
}
}
输出
Recovering from panic: Out of bound access for slice
Exiting normally
在上面的程序中,我们有一个函数checkAndPrint,它检查并打印传入参数的索引处的切片元素。如果传入的索引大于数组的长度,程序将会引发 panic。
我们还有另一个函数checkAndPrintWithRecover,它包含对
我们还有另一个函数checkAndPrintWithRecover,它包含对
-
带有recover的defer函数,名为handleOutOfBounds
-
调用checkAndPrint函数
所以我们在函数checkAndPrintWithRecover的开头有一个名为handleOutIfBounds的延迟函数。这个函数包含如下的 recover 函数调用。
if r := recover(); r != nil {
fmt.Println("Recovering from panic:", r)
}
checkAndPrint函数引发了 panic,但没有 recover 函数,相反,recover 的调用在checkAndPrintWithRecover函数中。我们将索引 2 传递给checkAndPrint函数,这个索引超出了边界。因此checkAndPrint引发了 panic,但程序仍然能够从 panic 中恢复,正如输出所示。这是因为 panic 可以在被调用的函数中恢复,并且在调用链中也可以恢复。
在 Go (Golang)中恢复二叉搜索树程序
来源:
golangbyexample.com/recover-binary-search-tree-golang/
目录
-
概述
-
程序
概述
给定一个二叉搜索树的根节点。两个二叉搜索树的节点已被交换。我们需要修复二叉树并恢复原始结构。
程序
下面是相应的程序
package main
import "fmt"
type TreeNode struct {
Val int
Left *TreeNode
Right *TreeNode
}
func recoverTree(root *TreeNode) {
var prev *TreeNode
var first *TreeNode
var mid *TreeNode
var last *TreeNode
recoverTreeUtil(root, &prev, &first, &mid, &last)
if first != nil && last != nil {
first.Val, last.Val = last.Val, first.Val
} else if first != nil && mid != nil {
first.Val, mid.Val = mid.Val, first.Val
}
}
func recoverTreeUtil(root *TreeNode, prev, first, mid, last **TreeNode) {
if root == nil {
return
}
recoverTreeUtil(root.Left, prev, first, mid, last)
if *prev == nil {
*prev = root
} else if *first == nil && (*prev).Val > root.Val {
*first = *prev
*mid = root
} else if (*prev).Val > root.Val {
*last = root
}
*prev = root
recoverTreeUtil(root.Right, prev, first, mid, last)
}
func main() {
root := TreeNode{Val: 2}
root.Left = &TreeNode{Val: 3}
root.Right = &TreeNode{Val: 1}
recoverTree(&root)
fmt.Println(root.Val)
fmt.Println(root.Left.Val)
fmt.Println(root.Right.Val)
}
输出
2
1
3
注意: 请查看我们的 Golang 高级教程。本系列教程内容详尽,我们尽量涵盖所有概念和示例。本教程适合希望获得专业知识和扎实理解 Golang 的人 – Golang 高级教程
如果你对了解所有设计模式如何在 Golang 中实现感兴趣的话。如果是,那么这篇文章就是为你准备的 – 所有设计模式 Golang
此外,请查看我们的系统设计教程系列 – 系统设计教程系列
Go(Golang)中的recover
函数返回值
来源:
golangbyexample.com/recover-return-value-golang/
目录
-
概述
-
示例
概述
recover
函数返回传递给panic
函数的值。因此,检查recover
函数的返回值是一种良好实践。如果返回值非空,则表示没有发生panic
,且recover
函数没有因panic
被调用。
示例
让我们看一个程序以充分理解它
package main
import "fmt"
func main() {
a := []string{"a", "b"}
checkAndPrint(a, 2)
fmt.Println("Exiting normally")
}
func checkAndPrint(a []string, index int) {
defer handleOutOfBounds()
if index > (len(a) - 1) {
panic("Out of bound access for slice")
}
fmt.Println(a[index])
}
func handleOutOfBounds() {
if r := recover(); r != nil {
fmt.Println("Recovering from panic:", r)
}
}
输出
Recovering from panic: Out of bound access for slice
Exiting normally
在上面的程序中,我们有一个函数checkAndPrint,它检查并打印传递给参数的索引处的切片元素。如果传递的索引大于数组的长度,则程序将发生panic
。我们在函数checkAndPrint的开始处添加了一个名为handleOutIfBounds的defer
函数。此函数包含对recover
函数的调用,如下所示。
if r := recover(); r != nil {
fmt.Println("Recovering from panic:", r)
}
recover函数将捕获panic
,我们也可以打印来自panic
的消息。
Recovering from panic: Out of bound access for slice
在recover
函数之后,程序继续执行,控制权返回到调用的函数,这里是main。这就是我们得到输出的原因。
Exiting normally
recover
函数返回传递给panic
函数的值。这就是我们在defer
函数handleOutofBounds中有下面代码的原因。
if r := recover(); r != nil
在这里,如果r为 nil,则表示没有发生panic
。因此,如果没有panic
,则对recover
的调用将返回 nil。
在 Go (Golang)中的协程中恢复 panic
来源:
golangbyexample.com/recover-panic-goroutine-go/
目录
-
概述
-
在相同协程中作为 panic 的 recover 函数
-
在不同协程中的 recover 函数作为 panic
概述
恢复协程中恐慌的情况有两种。
-
在相同协程中的 recover 函数作为panic**
-
在不同协程中的 recover 函数作为panic**
在第一种情况下,它将从 panic 中恢复。但需要注意的一个重要点是,recover 函数只能恢复在同一协程中发生的 panic。如果 panic 发生在不同协程中,而 recover 也在不同协程中,则无法恢复。
让我们看看两个例子的情况。
在相同协程中的 recover 函数作为 panic
package main
import "fmt"
func main() {
a := []string{"a", "b"}
go checkAndPrintWithRecover(a, 2)
fmt.Println("Exiting normally")
}
func checkAndPrintWithRecover(a []string, index int) {
defer handleOutOfBounds()
checkAndPrint(a, 2)
}
func checkAndPrint(a []string, index int) {
if index > (len(a) - 1) {
panic("Out of bound access for slice")
}
fmt.Println(a[index])
}
func handleOutOfBounds() {
if r := recover(); r != nil {
fmt.Println("Recovering from panic:", r)
}
}
输出
Exiting normally
Recovering from panic: Out of bound access for slice
在上述程序中,recover和panic位于同一协程中,因此能够从 panic 中恢复,正如从输出中所见。
在不同协程中的 recover 函数作为 panic
如前所述,在这种情况下无法从 panic 中恢复。
package main
import "fmt"
func main() {
a := []string{"a", "b"}
checkAndPrintWithRecover(a, 2)
fmt.Println("Exiting normally")
}
func checkAndPrintWithRecover(a []string, index int) {
defer handleOutOfBounds()
go checkAndPrint(a, 2)
}
func checkAndPrint(a []string, index int) {
if index > (len(a) - 1) {
panic("Out of bound access for slice")
}
fmt.Println(a[index])
}
func handleOutOfBounds() {
if r := recover(); r != nil {
fmt.Println("Recovering from panic:", r)
}
}
输出
Exiting normally
panic: Out of bound access for slice
goroutine 18 [running]:
main.checkAndPrint(0xc0000a6020, 0x2, 0x2, 0x2)
/Users/slohia/go/src/github.com/golang-examples/articles/tutorial/panicRecover/goroutine/main.go:19 +0xe2
created by main.checkAndPrintWithRecover
/Users/slohia/go/src/github.com/golang-examples/articles/tutorial/panicRecover/goroutine/main.go:14 +0x82
exit status 2
在上述程序中,我们在协程中有checkAndPrint,它在该协程中引发了panic。recover函数在调用协程中。正如您从输出中看到的,它并没有停止panic,因此您看到了一些信息。
Go(Golang)中的余数或模运算
来源:
golangbyexample.com/remainder-modulus-go-golang/
目录
-
概述
-
% 运算符
- 代码
-
浮点数的 Mod 函数
- 代码
-
IEEE 754 余数
- 代码
概述
在本教程中,我们将学习关于
-
% 运算符 – 适用于获取整数的余数
-
Mod 函数 – 也可以用于获取浮点数的余数
-
余数函数 – 可用于获取 IEEE 754 余数
% 运算符
Golang 有一个模运算符 (‘ %’),可用于获取两个整数相除后的余数。我们来看一个示例程序。
代码
package main
import (
"fmt"
)
func main() {
res := 4 % 2
fmt.Println(res)
res = 5 % 2
fmt.Println(res)
res = 8 % 3
fmt.Println(res)
}
输出:
0
1
2
浮点数的 Mod 函数
% 函数不适用于浮点数。要获取两个浮点数相除的余数,我们可以使用 math 包提供的 Mod 函数。以下是该函数的签名。它接受两个浮点数并返回一个浮点数,返回 x/y 的浮点余数,输出将采用 x 的符号。
func Mod(x, y float64) float64
Mod 函数的一些特殊情况是
-
Mod(±Inf, y) = NaN
-
Mod(NaN, y) = NaN
-
Mod(x, 0) = NaN
-
Mod(x, ±Inf) = x
-
Mod(x, NaN) = NaN
代码
package main
import (
"fmt"
"math"
)
func main() {
res := math.Mod(4, 2)
fmt.Println(res)
res = math.Mod(4.2, 2)
fmt.Println(res)
res = math.Mod(5, 2)
fmt.Println(res)
res = math.Mod(-5, 2)
fmt.Println(res)
}
输出
0
0.20000000000000018
1
-1
IEEE 754 余数
Go 的 math 包提供了一个 Remainder 方法,可以用来获取两个数的 IEEE 754 余数,其中一个作为分子,另一个作为分母。
你可以在这里阅读更多关于我们为什么需要 IEEE 754 余数 的信息 – stackoverflow.com/questions/26671975/why-do-we-need-ieee-754-remainder
以下是该函数的签名。它接受两个 float64 类型的数字并返回一个余数,这也是一个 IEEE 754 float64 余数。
func Remainder(x, y float64) float64
余数函数的一些特殊情况是
-
Remainder(±Inf, y) = NaN
-
Remainder(NaN, y) = NaN
-
Remainder(x, 0) = NaN
-
Remainder(x, ±Inf) = x
-
Remainder(x, NaN) = NaN
代码
package main
import (
"fmt"
"math"
)
func main() {
res := math.Remainder(4, 2)
fmt.Println(res)
res = math.Remainder(5, 2)
fmt.Println(res)
res = math.Remainder(5.5, 2)
fmt.Println(res)
res = math.Remainder(5.5, 1.5)
fmt.Println(res)
}
输出
0
1
-0.5
-0.5
从 Go 模块中移除依赖项(Golang)
来源:
golangbyexample.com/remove-dependency-golang/
目录
-
概述
-
示例
概述
要移除一个模块依赖项,我们需要做以下两件事
-
从模块的源文件中移除该依赖项的引用
-
运行
go mod tidy
命令。移除go.mod文件中不需要的所有依赖项。
示例
假设我们有一个模块,导入名为“learn”的模块,包含以下go.mod
文件和learn.go
文件。
go.mod
module learn
go 1.14
require github.com/pborman/uuid v1.2.1
learn.go
package main
import (
"fmt"
"strings"
"github.com/pborman/uuid"
)
func main() {
uuidWithHyphen := uuid.NewRandom()
uuid := strings.Replace(uuidWithHyphen.String(), "-", "", -1)
fmt.Println(uuid)
}
注意我们在learn.go中导入了该依赖项,并且这个依赖项也被添加到go.mod文件中
"github.com/pborman/uuid"
现在让我们尝试从上述模块完全移除这个依赖项。命令go mod tidy将从go.mod文件中移除该依赖项,如果它在源文件中不需要。为了说明这一点,让我们删除之前创建的learn.go文件。现在运行命令
go mod tidy -v
它将给出以下输出
unused github.com/pborman/uuid
现在检查go.mod文件的内容。它将如下所示
module learn
go 1.14
那
require github.com/pborman/uuid v1.2.1
该行将被移除,因为在任何源文件中都不需要它。此外,github.com/pborman/uuid及其依赖项的所有条目也将从go.sum文件中移除。
在 Go(Golang)中原地移除数组中的给定值的所有出现
来源:
golangbyexample.com/remove-element-golang/
目录
-
概述
-
程序
概述
给定一个整数数组和一个目标元素。从数组中移除所有该目标元素的出现。删除必须在原地进行。
Input: [1, 4, 2, 5, 4]
Target: 4
Output: [1, 2, 5]
Input: [1, 2, 3]
Target:3
Output: [1, 2]
程序
这里是相应的程序。
package main
import (
"fmt"
)
func removeElement(nums []int, val int) []int {
lenNums := len(nums)
k := 0
for i := 0; i < lenNums; {
if nums[i] != val {
nums[k] = nums[i]
k++
}
i++
}
return nums[0:k]
}
func main() {
output := removeElement([]int{1, 4, 2, 5, 4}, 4)
fmt.Println(output)
output = removeElement([]int{1, 2, 3}, 3)
fmt.Println(output)
}
输出
[1 2 5]
[1 2]
注意: 请查看我们的 Golang 高级教程。本系列的教程内容详尽,我们尝试用实例覆盖所有概念。本教程适合那些希望获得专业知识和对 Golang 有深入理解的人 - Golang 高级教程
如果你有兴趣了解所有设计模式如何在 Golang 中实现。如果是的话,这篇文章适合你 - 所有设计模式 Golang
在 Go (Golang)中去除浮点数的小数点
来源:
golangbyexample.com/remove-decimal-float-go/
目录
-
概述
-
代码:
概述
math包提供了一个Trunc方法,可用于移除浮点数的小数点并将其转换为整数
以下是该函数的签名。它接受一个浮点数作为输入,并返回一个浮点数。
func Trunc(x float64) float64\
代码:
package main
import (
"fmt"
"math"
)
func main() {
res := math.Trunc(1.6)
fmt.Println(res)
res = math.Trunc(-1.6)
fmt.Println(res)
res = math.Trunc(1)
fmt.Println(res)
}
输出:
1
-1
1
在 Go(Golang)中从已排序的数组中移除重复项
来源:
golangbyexample.com/remove-duplicates-sorted-array-golang/
目录
-
概述
-
程序
概述
目标是从一个已排序的数组中移除重复项。
示例
Input: [1, 1, 1, 2]
Output: [1, 2]
Input: [1, 2, 3, 3]
Output: [1, 2, 3]
程序
以下是相同的程序
package main
import "fmt"
func main() {
input := []int{1, 1, 1, 2}
output := removeDuplicates(input)
fmt.Println(output)
input = []int{1, 2, 3, 3}
output = removeDuplicates(input)
fmt.Println(output)
}
func removeDuplicates(nums []int) []int {
lenArray := len(nums)
k := 0
for i := 0; i < lenArray; {
nums[k] = nums[i]
k++
for i+1 < lenArray && nums[i] == nums[i+1] {
i++
}
i++
}
return nums[0:k]
}
输出
[1 2]
[1 2 3]
注意:查看我们的 Golang 高级教程。本系列教程内容详尽,我们尝试覆盖所有概念并附有示例。本教程适合那些希望获得专业知识和扎实理解 Golang 的人 - Golang 高级教程
如果你有兴趣了解所有设计模式如何在 Golang 中实现。如果是的话,这篇文章适合你 - 所有设计模式 Golang
在 Go (Golang)中删除链表元素的程序
来源:
golangbyexample.com/remove-linked-list-elements-golang/
目录
-
概述
-
程序
概述
给定一个链表和一个值,删除链表中所有值等于给定值的节点。
示例 1
Input: [1, 2, 1, 3, 6], 1
Output: [2, 3, 6]
示例 2
Input: [2, 2, 3], 2
Output: [3]
程序
下面是相应的程序
package main
import "fmt"
type ListNode struct {
Val int
Next *ListNode
}
type SingleList struct {
Len int
Head *ListNode
}
func (s *SingleList) AddFront(num int) *ListNode {
ele := &ListNode{
Val: num,
}
if s.Head == nil {
s.Head = ele
} else {
ele.Next = s.Head
s.Head = ele
}
s.Len++
return ele
}
func removeElements(head *ListNode, val int) *ListNode {
var prev *ListNode
curr := head
for curr != nil {
if curr.Val == val {
if prev == nil {
head = curr.Next
} else {
prev.Next = curr.Next
}
} else {
prev = curr
}
curr = curr.Next
}
return head
}
func main() {
first := initList()
first.AddFront(6)
first.AddFront(3)
first.AddFront(1)
first.AddFront(2)
first.AddFront(1)
result := removeElements(first.Head, 1)
fmt.Println("Resultant First List")
result.Traverse()
first = initList()
first.AddFront(3)
first.AddFront(2)
first.AddFront(2)
fmt.Println("\nResultant Second List")
result = removeElements(first.Head, 2)
result.Traverse()
}
func initList() *SingleList {
return &SingleList{}
}
func (l *ListNode) Traverse() {
for l != nil {
fmt.Println(l.Val)
l = l.Next
}
}
输出
Resultant First List
2
3
6
Resultant Second List
3
注意: 查看我们的 Golang 高级教程。该系列教程内容详尽,我们努力涵盖所有概念及示例。本教程适合希望获得专业知识和深入理解 Golang 的学习者 – Golang 高级教程
如果你对理解如何在 Golang 中实现所有设计模式感兴趣。如果是的话,这篇文章适合你 – 所有设计模式 Golang
另外,可以在这里查看我们的系统设计教程系列 – 系统设计教程系列
在 Go (Golang) 中删除或去掉字符串中的所有空白字符。
来源:
golangbyexample.com/remove-all-white-spaces-string-golang/
strings.ReplaceAll 函数可以用来去掉 Golang 字符串中的所有空白字符。以下是该函数的签名:
func ReplaceAll(s, old, new string) string
-
s(第一个参数)是输入字符串。
-
old(第二个参数)是要被替换的字符串,new(第三个参数)是替换后的字符串。
有效代码:
package main
import (
"fmt"
"strings"
)
func main() {
sample := " This is a sample string "
noSpaceString := strings.ReplaceAll(sample, " ", "")
fmt.Println(noSpaceString)
}
输出:
Thisisasamplestring
- 所有* 修剪
在 Go (Golang)中重命名文件或文件夹
来源:
golangbyexample.com/rename-file-folder-golang/
目录
-
概述
-
代码
-
重命名文件
-
重命名文件夹
-
概述
可以使用 os.Rename()函数来重命名文件或文件夹。下面是该函数的签名。
func Rename(old, new string) error
old和new也可以是完整路径。如果old和new路径不在同一目录中,则os.Rename()函数的行为与移动文件或文件夹相同。
代码
重命名文件
下面是重命名文件的代码
package main
import (
"log"
"os"
)
func main() {
//Create a file
file, err := os.Create("temp.txt")
if err != nil {
log.Fatal(err)
}
defer file.Close()
//Change permission so that it can be moved
err = os.Chmod("temp.txt", 0777)
if err != nil {
log.Println(err)
}
err = os.Rename("temp.txt", "newTemp.txt")
if err != nil {
log.Fatal(err)
}
}
输出
首先,它将在当前工作目录中创建一个名为 temp.txt 的文件。然后它将其重命名为 newTemp.txt。
重命名文件夹
下面是重命名文件夹的代码
package main
import (
"log"
"os"
)
func main() {
//Create a directory
err := os.Mkdir("temp", 0755)
if err != nil {
log.Fatal(err)
}
err = os.Rename("temp", "newTemp")
if err != nil {
log.Fatal(err)
}
}
输出:
首先,它将在当前工作目录中创建一个名为 temp 的文件夹。然后它将其重命名为 newTemp。
- 文件* 文件夹* go* golang* 重命名*
在 Go (Golang) 中重复一个字符串多次
来源:
golangbyexample.com/repeat-string-golang/
目录
-
概述
-
程序
概述
strings.Repeat 方法可用于在 Go (Golang) 中多次重复一个字符串
这是 Go 字符串包中该函数的链接
pkg.go.dev/strings#Repeat
这是该方法的签名
func Repeat(s string, count int) string
第一个参数是原始字符串,count 是字符串需要重复的次数
程序
这是相同内容的程序
package main
import (
"fmt"
"strings"
)
func main() {
copy := strings.Repeat("a", 2)
fmt.Println(copy)
copy = strings.Repeat("abc", 3)
fmt.Println(copy)
}
输出:
aa
abcabcabc
注意: 请查看我们的 Golang 高级教程。本系列的教程内容详尽,我们努力覆盖所有概念及示例。本教程适合那些希望获得专业知识和深入理解 Golang 的人 – Golang 高级教程
如果你有兴趣了解所有设计模式如何在 Golang 中实现。如果是的话,这篇文章就是为你准备的 – 所有设计模式 Golang
在 Go (Golang) 中用另一个字符替换字符串中的字符
来源:
golangbyexample.com/replace-character-string-go/
目录
-
概述
-
代码:
概述
在 GO 中,字符串是 UTF-8 编码的。GO 的 strings 包提供了一个 Replace 方法,可以用来在给定字符串中将一个字符替换为另一个字符。它返回字符串的副本。
以下是该函数的签名。
-
提供要被替换的字符作为 old。
-
提供你想替换的字符作为 new。
-
n 表示替换的次数。如果 n 为 -1,则所有 old 的实例将被替换为 new。
func Replace(s, old, new string, n int)
让我们看看工作代码。
代码:
package main
import (
"fmt"
"strings"
)
func main() {
//It will replaces 1 instance of a with 1
res := strings.Replace("abcdabxyabr", "a", "1", 1)
fmt.Println(res)
//It will replace all instances of a with 1
res = strings.Replace("abcdabxyabr", "a", "1", -1)
fmt.Println(res)
}
输出:
1bcdabxyabr
1bcd1bxy1br
```*
<!--yml
分类:未分类
日期:2024-10-13 06:12:57
-->
# 在 Go (Golang)中将一个子字符串的所有实例替换为另一个
> 来源:[`golangbyexample.com/replace-all-instances-substring-go/`](https://golangbyexample.com/replace-all-instances-substring-go/)
目录
+ 概述
+ 代码:
# **概述**
在 GO 中,字符串是 UTF-8 编码的。GO 的**strings**包提供了一个**ReplaceAll**方法,可以用来替换给定子字符串的所有不重叠实例为一个新的子字符串。它返回字符串的副本。
下面是该函数的签名。该函数将在字符串**s**中替换所有不重叠的**old**实例为**new**。如果**old**为空,则它将在字符串**s**中的每个有效的 UTF-8 字节序列之间插入**new**。
```go
func ReplaceAll(s, old, new string) string
让我们来看一下工作的代码
代码:
package main
import (
"fmt"
"strings"
)
func main() {
res := strings.ReplaceAll("abcdabxyabr", "ab", "12")
fmt.Println(res)
res = strings.ReplaceAll("abcdabxyabr", "", "12")
fmt.Println(res)
}
输出
12cd12xy12r
12a12b12c12d12a12b12x12y12a12b12r12
```*
<!--yml
分类:未分类
日期:2024-10-13 06:13:01
-->
# 在 Go (Golang)中用另一个子字符串替换一些子字符串的实例
> 来源:[`golangbyexample.com/replace-some-instances-substring-go/`](https://golangbyexample.com/replace-some-instances-substring-go/)
目录
+ 概述
+ 代码:
# **概述**
在 GO 中,字符串是 UTF-8 编码的。GO 的**strings**包提供了一个**Replace**方法,可用于将给定子字符串的一些不重叠实例替换为新子字符串。它返回字符串的副本。
下面是函数的签名。
```go
func Replace(s, old, new string, n int)
-
该函数将在字符串s中将所有不重叠的old实例替换为new。
-
如果old为空,则在字符串s中的每个有效 UTF-8 字节序列之间插入new。
-
如果n为负,则所有old的实例将被替换为new。
让我们看看工作代码。
代码:
package main
import (
"fmt"
"strings"
)
func main() {
res := strings.Replace("abcdabxyabr", "ab", "12", 1)
fmt.Println(res)
res = strings.Replace("abcdabxyabr", "ab", "12", -1)
fmt.Println(res)
}
输出:
12cdabxyabr
12cd12xy12r
```*
<!--yml
类别:未分类
日期:2024-10-13 06:07:33
-->
# 在 Go (Golang) 中表示出生日期
> 来源:[`golangbyexample.com/dob-golang/`](https://golangbyexample.com/dob-golang/)
**time** 包的 **time.Date** 函数可用于创建一个特定日期,以表示出生日期。
请参见以下示例
+ `getDOB` 是一个接受年份、月份和日期并返回日期的函数。
```go
package main
import (
"fmt"
"time"
)
const (
//TimeFormat1 to format date into
TimeFormat1 = "2006-01-02"
//TimeFormat2 Other format to format date time
TimeFormat2 = "January 02, 2006"
)
func main() {
dob := getDOB(2011, 4, 2)
fmt.Println(dob.Format(TimeFormat1))
fmt.Println(dob.Format(TimeFormat2))
}
func getDOB(year, month, day int) time.Time {
dob := time.Date(year, time.Month(month), day, 0, 0, 0, 0, time.UTC)
return dob
}
输出:
2011-04-02
April 02, 2011
- 日期* 出生日期* 包
在 Go (Golang) 中返回 200 (状态正常) 状态码的 HTTP 响应 -P
来源:
golangbyexample.com/200-http-status-response-golang/
目录
-
概述
-
程序
概述
Golang 的 net/http 包提供了可以用来返回不同状态码的状态码常量 - golang.org/src/net/http/status.go
同样可以用来返回 200 (状态正常) HTTP 状态码。 HTTP 200 状态码由以下常量定义。
http.StatusOK
在这篇文章中,我们还将看到如何返回 JSON 主体以及 200 (状态正常) 状态码。
程序
以下是相同的程序
package main
import (
"encoding/json"
"log"
"net/http"
)
func main() {
handler := http.HandlerFunc(handleRequest)
http.Handle("/example", handler)
http.ListenAndServe(":8080", nil)
}
func handleRequest(w http.ResponseWriter, r *http.Request) {
w.WriteHeader(http.StatusOK)
w.Header().Set("Content-Type", "application/json")
resp := make(map[string]string)
resp["message"] = "Status OK"
jsonResp, err := json.Marshal(resp)
if err != nil {
log.Fatalf("Error happened in JSON marshal. Err: %s", err)
}
w.Write(jsonResp)
return
}
在这里,我们使用 WriteHeader 函数来指定 200 HTTP 状态码,并使用 Write 函数返回响应主体。上述代码将以下 JSON 请求主体作为响应返回。
{"message":"Status OK"}
运行上述程序。这将在你的本地机器上启动一个 8080 端口的服务器。现在对服务器进行以下 curl 调用。
curl -v -X POST http://localhost:8080/example
以下将是输出。
* Connected to localhost (::1) port 8080 (#0)
> POST /example HTTP/1.1
> Host: localhost:8080
> User-Agent: curl/7.54.0
> Accept: */*
>
< HTTP/1.1 200 OK
< Date: Sat, 10 Jul 2021 09:42:59 GMT
< Content-Length: 23
< Content-Type: text/plain; charset=utf-8
<
* Connection #0 to host localhost left intact
{"message":"Status OK"}
正如你从输出中看到的,它将正确返回 200 状态码以及主体。
你也可以直接将 200 传递给 WriteHeader 函数以发送 200 响应。
w.WriteHeader(200)
这同样有效。试试看。
同时,请查看我们的 Golang 高级教程系列 - Golang 高级教程
- 200* go* golang*
在 Go(Golang)HTTP 响应中返回 201(状态创建)状态码。
来源:
golangbyexample.com/201-http-status-response-golang/
目录
概述
- 程序
概述
net/http包提供了状态码常量,可用于返回不同的状态码 - golang.org/src/net/http/status.go
同样可以用于返回 201(状态创建)HTTP 状态码。HTTP 201 状态码由以下常量定义。
http.StatusCreated
在这篇文章中,我们还将看到如何返回 JSON 体以及 201(状态创建)状态码。
程序
以下是相同的程序。
package main
import (
"encoding/json"
"log"
"net/http"
)
func main() {
handler := http.HandlerFunc(handleRequest)
http.Handle("/example", handler)
http.ListenAndServe(":8080", nil)
}
func handleRequest(w http.ResponseWriter, r *http.Request) {
w.WriteHeader(http.StatusCreated)
w.Header().Set("Content-Type", "application/json")
resp := make(map[string]string)
resp["message"] = "Status Created"
jsonResp, err := json.Marshal(resp)
if err != nil {
log.Fatalf("Error happened in JSON marshal. Err: %s", err)
}
w.Write(jsonResp)
return
}
在这里,我们使用WriteHeader函数指定 201 HTTP 状态码,并使用Write函数返回响应体。上述代码返回以下 JSON 请求体作为响应。
{"message":"Status Created"}
运行上述程序,它将在你的本地机器上启动一个 8080 端口的服务器。现在进行以下 curl 调用到服务器。
curl -v -X POST http://localhost:8080/example
以下将是输出。
* Connected to localhost (::1) port 8080 (#0)
> POST /example HTTP/1.1
> Host: localhost:8080
> User-Agent: curl/7.54.0
> Accept: */*
>
< HTTP/1.1 201 Created
< Date: Sat, 10 Jul 2021 10:40:33 GMT
< Content-Length: 28
< Content-Type: text/plain; charset=utf-8
<
* Connection #0 to host localhost left intact
{"message":"Status Created"}
如你所见,输出将正确返回 201 状态码以及主体。
你也可以直接将 201 传递给 WriteHeader 函数以发送 201 响应。
w.WriteHeader(201)
这同样工作正常。试试看。
此外,查看我们的 Golang 进阶教程系列 - Golang 进阶教程。
- 201* go* golang*
在 Go(Golang)中返回 202(StatusAccepted)HTTP 响应
来源:
golangbyexample.com/202-status-http-response-go/
目录
-
概述
-
程序
概述
net/http包提供了状态码常量,可以用于返回不同的状态码 - golang.org/src/net/http/status.go
同样也可以用于返回 202(StatusAccepted)HTTP 状态码。HTTP 202 状态码由下面的常量定义。
http.StatusAccepted
在本文中,我们还将看到如何返回带有 202(StatusAccepted)状态码的 JSON 主体
程序
下面是相应的程序
package main
import (
"encoding/json"
"log"
"net/http"
)
func main() {
handler := http.HandlerFunc(handleRequest)
http.Handle("/example", handler)
http.ListenAndServe(":8080", nil)
}
func handleRequest(w http.ResponseWriter, r *http.Request) {
w.WriteHeader(http.StatusAccepted)
w.Header().Set("Content-Type", "application/json")
resp := make(map[string]string)
resp["message"] = "Status Accepted"
jsonResp, err := json.Marshal(resp)
if err != nil {
log.Fatalf("Error happened in JSON marshal. Err: %s", err)
}
w.Write(jsonResp)
return
}
在这里我们使用WriteHeader函数来指定 202 HTTP 状态码,并使用Write函数返回响应主体。上述代码将以下 JSON 请求主体返回作为响应
{"message":"Status Accepted"}
运行上述程序。它将在你的本地机器上启动一个 8080 端口的服务器。现在对服务器进行下面的 curl 调用。
curl -v -X POST http://localhost:8080/example
下面将是输出结果
* Connected to localhost (::1) port 8080 (#0)
> POST /example HTTP/1.1
> Host: localhost:8080
> User-Agent: curl/7.54.0
> Accept: */*
>
< HTTP/1.1 202 Accepted
< Date: Sat, 10 Jul 2021 17:42:27 GMT
< Content-Length: 29
< Content-Type: text/plain; charset=utf-8
<
* Connection #0 to host localhost left intact
{"message":"Status Accepted"}
正如你从输出中看到的,它将正确返回 202 状态码以及主体。
你也可以直接将 202 传递给 WriteHeader 函数以发送 202 响应。
w.WriteHeader(202)
这同样有效。试试看。
另外,查看我们的 Golang 高级教程系列 - Golang 高级教程
在 Go(Golang)中返回 400(错误请求)状态码的 HTTP 响应
来源:
golangbyexample.com/400-http-status-response-golang/
目录
-
概述
-
程序
概述
Golang 的net/http包提供了状态码常量,可用于返回不同的状态码 - golang.org/src/net/http/status.go
同样也可以用来返回 400(错误请求)HTTP 状态码。HTTP 400 状态码由以下常量定义。
在这篇文章中,我们还将看到如何在返回 400(错误请求)状态码的同时返回 JSON 主体。
程序
以下是相同的程序
package main
import (
"net/http"
)
func main() {
handler := http.HandlerFunc(handleRequest)
http.Handle("/example", handler)
http.ListenAndServe(":8080", nil)
}
func handleRequest(w http.ResponseWriter, r *http.Request) {
w.WriteHeader(http.StatusBadRequest)
return
}
这里我们使用WriteHeader函数来指定 HTTP 状态码。
运行上述程序。它将在你的本地机器上启动一个 8080 端口的服务器。现在向服务器发出以下 curl 调用。
curl -v -X POST http://localhost:8080/example
以下将是输出
* Connected to localhost (::1) port 8080 (#0)
> POST /example HTTP/1.1
> Host: localhost:8080
> User-Agent: curl/7.54.0
> Accept: */*
>
< HTTP/1.1 400 Bad Request
< Date: Sat, 10 Jul 2021 05:50:32 GMT
< Content-Length: 0
<
* Connection #0 to host localhost left intact
从输出中可以看到,它将正确返回 400 状态码。如果我们还想返回 JSON 错误主体,那么以下是相应的代码。
package main
import (
"encoding/json"
"log"
"net/http"
)
func main() {
handler := http.HandlerFunc(handleRequest)
http.Handle("/example", handler)
http.ListenAndServe(":8080", nil)
}
func handleRequest(w http.ResponseWriter, r *http.Request) {
w.WriteHeader(http.StatusBadRequest)
w.Header().Set("Content-Type", "application/json")
resp := make(map[string]string)
resp["message"] = "Bad Request"
jsonResp, err := json.Marshal(resp)
if err != nil {
log.Fatalf("Error happened in JSON marshal. Err: %s", err)
}
w.Write(jsonResp)
return
}
上述代码在响应中返回以下 JSON 请求主体。
{"message":"Bad Request"}
运行上述程序。它将在你的本地机器上启动一个 8080 端口的服务器。现在向服务器发出以下 curl 调用。
curl -v -X POST http://localhost:8080/example
以下将是输出
* Connected to localhost (::1) port 8080 (#0)
> POST /example HTTP/1.1
> Host: localhost:8080
> User-Agent: curl/7.54.0
> Accept: */*
>
< HTTP/1.1 400 Bad Request
< Date: Sat, 10 Jul 2021 05:58:42 GMT
< Content-Length: 25
< Content-Type: text/plain; charset=utf-8
<
* Connection #0 to host localhost left intact
{"message":"Bad Request"}
从输出中可以看到,它正确返回了 400 状态码及其主体。
你也可以直接将 400 传递给 WriteHeader 函数以发送 400 响应。
w.WriteHeader(400)
这也能正常工作。试试看。
另外,查看我们的 Golang 进阶教程系列 - Golang 进阶教程
- 400* go* golang*