透過示例學習 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*