通过示例学习-Go-语言-2023-二十八-

龙哥盟 / 2024-10-23 / 原文

通过示例学习 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

程序

以下是相同程序,展示CookieCookies方法的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,它包含对

  • 带有recoverdefer函数,名为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的开始处添加了一个名为handleOutIfBoundsdefer函数。此函数包含对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

在上述程序中,recoverpanic位于同一协程中,因此能够从 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,它在该协程中引发了panicrecover函数在调用协程中。正如您从输出中看到的,它并没有停止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

oldnew也可以是完整路径。如果oldnew路径不在同一目录中,则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*