透過示例學習-Go-語言-2023-八-

绝不原创的飞龙發表於2024-10-19

透過示例學習 Go 語言 2023(八)

Go (Golang) 中的 Cookies

來源:golangbyexample.com/cookies-golang/

目錄

** 什麼是 cookie

  • 在 golang 中設定 cookie

    • 在發起請求時設定 cookie。

    • 在響應傳入請求時設定 cookie

  • 在 golang 中讀取 cookie

Cookies 是一種在客戶端儲存資訊的方式。客戶端可以是瀏覽器、移動應用程式或任何發起 HTTP 請求的事物。Cookies 基本上是儲存在瀏覽器快取記憶體中的一些檔案。當您瀏覽任何支援 cookies 的網站時,會在 cookie 中記錄與您活動相關的某種資訊。這些資訊可以是任何內容。簡而言之,cookies 儲存使用者活動的歷史資訊。這些資訊儲存在客戶端的計算機上。由於 cookie 儲存在檔案中,因此即使使用者關閉瀏覽器視窗或重啟計算機,這些資訊也不會丟失。cookie 還可以儲存登入資訊。實際上,諸如令牌等登入資訊通常僅儲存在 cookies 中。cookies 是按域儲存的。屬於特定域的本地儲存 cookies 在每個請求中傳送到該域。它們在每個請求中作為頭的一部分傳送。因此,cookie 本質上只是一種頭。

您可以在這裡閱讀關於 HTTP cookie 的一般資訊 – en.wikipedia.org/wiki/HTTP_cookie

Cookies 可以傳送

  • 作為 HTTP 客戶端的 Cookie 頭

  • 作為 HTTP 伺服器響應中的 Set-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
}

詳細資訊請參見 tools.ietf.org/html/rfc6265 中上述 cookie 的每個欄位。

讓我們詳細瞭解與 cookies 相關的兩個方面

  • 在 golang 中設定 cookie

  • 讀取 cookie

我們已經提到 cookie 只是一個頭。因此,要設定特定的 cookie,我們只需設定該頭。

有兩種情況

  • 在發起請求時設定 cookie。

  • 在響應傳入請求時設定 cookie

讓我們詳細瞭解每一個

這是 golang 作為 HTTP 客戶端的情況。AddCookie 方法可用於新增 cookie。如果我們對兩個不同的名稱和值呼叫此方法,那麼這兩個名稱和值都將新增到結果 cookie 中

package main
import (
    "fmt"
    "log"
    "net/http"
    "net/http/cookiejar"
)
var client http.Client
func init() {
    jar, err := cookiejar.New(nil)
    if err != nil {
        log.Fatalf("Got error while creating cookie jar %s", err.Error())
    }
    client = http.Client{
        Jar: jar,
    }
}
func main() {
    cookie := &http.Cookie{
        Name:   "token",
        Value:  "some_token",
        MaxAge: 300,
    }
    cookie2 := &http.Cookie{
        Name:   "clicked",
        Value:  "true",
        MaxAge: 300,
    }
    req, err := http.NewRequest("GET", "http://google.com", nil)
    if err != nil {
        log.Fatalf("Got error %s", err.Error())
    }
    req.AddCookie(cookie)
    req.AddCookie(cookie2)
    for _, c := range req.Cookies() {
        fmt.Println(c)
    }
    resp, err := client.Do(req)
    if err != nil {
        log.Fatalf("Error occured. Error is: %s", err.Error())
    }
    defer resp.Body.Close()
    fmt.Printf("StatusCode: %d\n", resp.StatusCode)
}

輸出

token=some_token
clicked=true
StatusCode: 200

在上述程式中,HTTP 客戶端新增了兩個 cookies。這兩個 cookies 將在呼叫 google.com 時傳送。

golang 中的 HTTP 客戶端還允許您指定一個 CookieJar,該 jar 管理在進行外部 HTTP 請求時儲存和傳送 cookies。顧名思義,可以把它看作一個裝有 cookies 的 jar。

HTTP 客戶端以兩種方式使用此 jar。

  • 在此 Jar 中新增 cookies。您可以顯式地將 cookies 新增到此 jar。如果伺服器在響應頭中傳送 Set-Cookies 頭,cookies 也將被新增到 jar 中。所有在 Set-Cookie 頭中指定的 cookies 將被新增。

  • 在進行任何外部 HTTP 請求時諮詢此 jar。它檢查此 jar 以瞭解特定域需要傳送哪些 cookies。

有關 golang 中 CookieJar 的更多資訊,可以參考此連結 golangbyexample.com/cookiejar-golang/

這是 golang 作為 HTTP 伺服器的情況。http.ResponseWriter 結構提供了一個方便的方法來設定 cookie。下面是該方法的簽名。

func SetCookie(w ResponseWriter, cookie *Cookie)

此方法用於在 ResponseWriter 上設定 cookies。它向響應頭新增一個 Set-Cookie 頭。此 Set-Cookie 頭用於傳送在客戶端或瀏覽器端設定的 cookie。然後,當客戶端向伺服器發出後續呼叫時,該 cookie 將被髮送回伺服器。

以下是相應的程式。

package main
import (
    "net/http"
)
func main() {
    docHandler := http.HandlerFunc(docHandler)
    http.Handle("/doc", docHandler)
    http.ListenAndServe(":8080", nil)
}
func docHandler(w http.ResponseWriter, r *http.Request) {
    cookie := &http.Cookie{
        Name:   "id",
        Value:  "abcd",
        MaxAge: 300,
    }
    http.SetCookie(w, cookie)
    w.WriteHeader(200)
    w.Write([]byte("Doc Get Successful"))
    return
}

使用以下命令執行上述程式。

go run main.go

伺服器將在 8080 埠啟動。

現在從瀏覽器發起 API 呼叫 localhost:8080/doc。伺服器在響應中傳送了以下 Set-Cookie

Set-Cookie: id=abcd; Max-Age=300

這在 API 呼叫的響應頭中也可見。見下圖。

![](https://gitee.com/OpenDocCN/geekdoc-golang-zh/raw/master/docs/go-exam-2023/img/5743ff6b7299452f20052240e39f56a7.png)

有關 Set-Cookie 頭的更多詳細資訊,請參閱此 link。該連結包含了解 Set-Cookie 頭在 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)
}

以下是相應的程式,演示 http.Request 結構的 CookieCookies 方法。

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

這就是我們如何列印所有 cookies。

for _, c := range r.Cookies() {
     fmt.Println(c)
}

它輸出我們在 curl 呼叫中傳送的 cookie 名稱-值對。

id=abcd
token=some_token

這就是關於 golang 中的 cookie 的所有內容。希望你喜歡這個教程。請在評論中分享反饋。

另外,檢視我們的 Golang 高階教程系列 – Golang 高階教程

在 Go 語言中複製陣列或切片

來源:golangbyexample.com/copy-an-array-or-slice-golang/

目錄

  • 概述

  • 複製一個陣列

  • 複製一個切片

概述

在 Go 語言中,陣列是值型別,而切片是引用型別。因此,陣列或切片如何複製到另一個陣列或切片的方式是不同的。

複製一個陣列

如上所述,陣列在 Go 語言中是值型別。因此,陣列變數名不是指向第一個元素的指標,而是表示整個陣列。當

  • 一個陣列變數被賦值給另一個陣列變數。

  • 一個陣列變數作為引數傳遞給一個函式。

我們用一個例子來說明上述要點

package main

import "fmt"

func main() {
	sample1 := [2]string{"a", "b"}
	fmt.Printf("Sample1 Before: %v\n", sample1)
	sample2 := sample1
	sample2[1] = "c"
	fmt.Printf("Sample1 After assignment: %v\n", sample1)
	fmt.Printf("Sample2: %v\n", sample2)
	test(sample1)
	fmt.Printf("Sample1 After Test Function Call: %v\n", sample1)
}
func test(sample [2]string) {
	sample[0] = "d"
	fmt.Printf("Sample in Test function: %v\n", sample)
}

輸出

Sample1 Before: [a b]
Sample1 After assignment: [a b]
Sample2: [a c]
Sample in Test function: [d b]
Sample1 After Test Function Call: [a b]

在上述例子中,

  • 我們將sample1賦值給sample2,然後在sample2的 0 索引處改變為不同的值。之後,當我們列印sample1時,發現它沒有改變。這是因為當我們將sample1賦值給sample2時,會建立一個副本,改變sample2不會影響sample1

  • 我們將sample1傳遞給測試函式,然後在測試函式的 0 索引處再次改變其值。之後,當我們列印sample1時,發現它沒有改變。原因相同,當sample1作為引數傳遞給測試函式時,會建立sample1的一個副本。

複製一個切片

Go 的builtin包提供了一個copy函式,可以用來複制切片。下面是這個函式的簽名。它返回複製的元素數量。

func copy(dst, src []Type) int

在使用 copy 函式時,有兩種情況需要考慮:

  • 如果src的長度大於dst的長度,則複製的元素數量為dst的長度

  • 如果dst的長度大於src的長度,則複製的元素數量為src的長度

基本上,複製的元素數量是(src, dst)長度的最小值。

還要注意,一旦複製完成,dst中的任何更改將不會反映在src中,反之亦然。

package main

import "fmt"

func main() {
    src := []int{1, 2, 3, 4, 5}
    dst := make([]int, 5)

    numberOfElementsCopied := copy(dst, src)
    fmt.Printf("Number Of Elements Copied: %d\n", numberOfElementsCopied)
    fmt.Printf("dst: %v\n", dst)
    fmt.Printf("src: %v\n", src)

    //After changing numbers2
    dst[0] = 10
    fmt.Println("\nAfter changing dst")
    fmt.Printf("dst: %v\n", dst)
    fmt.Printf("src: %v\n", src)
}

輸出

Number Of Elements Copied: 5
dst: [1 2 3 4 5]
src: [1 2 3 4 5]

After changing dst
dst: [10 2 3 4 5]
src: [1 2 3 4 5]
```*


<!--yml

類別:未分類

日期:2024-10-13 06:18:40

-->

# Go 中的複製函式(Golang)

> 來源:[`golangbyexample.com/copy-function-in-golang/`](https://golangbyexample.com/copy-function-in-golang/)

Go 的 **builtin** 包提供了 **copy** 函式,可以用於複製切片。以下是此函式的簽名。它接收兩個切片 **dst** 和 **src**,並將資料從 **src** 複製到 **dst**。它返回複製的元素數量。

```go
func copy(dst, src []Type) int

根據簽名,複製函式可以用於從 src 複製不同型別的切片到 dst。在使用複製函式時,有兩種情況需要考慮:

  • 如果 src 的長度大於 dst 的長度,則複製的元素數量為 dst 的長度。

  • 如果 dst 的長度大於 src 的長度,則複製的元素數量為 src 的長度。

基本上,複製的元素數量為 (src, dst) 長度的最小值。

還要注意,一旦複製完成,dst 中的任何更改將不會反映在 src 中,反之亦然,除非 srcdst 引用同一個切片。

一個簡單的整數型別複製示例,說明上述要點。

package main

import "fmt"

func main() {
    src := []int{1, 2, 3, 4, 5}
    dst := make([]int, 5)
    numberOfElementsCopied := copy(dst, src)

    fmt.Printf("Number Of Elements Copied: %d\n", numberOfElementsCopied)
    fmt.Printf("dst: %v\n", dst)
    fmt.Printf("src: %v\n", src)

    //After changing dst
    dst[0] = 10
    fmt.Println("\nAfter changing dst")
    fmt.Printf("dst: %v\n", dst)
    fmt.Printf("src: %v\n", src)

    //Length of destination is less than length of source
    dst = make([]int, 4)
    numberOfElementsCopied = copy(dst, src)
    fmt.Println("\nLength of dst less than src")
    fmt.Printf("Number Of Elements Copied: %d\n", numberOfElementsCopied)
    fmt.Printf("dst: %v\n", dst)
    fmt.Printf("src: %v\n", src)

    //Length of destination is greater than length of source
    dst = make([]int, 6)
    numberOfElementsCopied = copy(dst, src)
    fmt.Println("\nLength of dst less than src")
    fmt.Printf("Number Of Elements Copied: %d\n", numberOfElementsCopied)
    fmt.Printf("dst: %v\n", dst)
    fmt.Printf("src: %v\n", src)
}

輸出

Number Of Elements Copied: 5
dst: [1 2 3 4 5]
src: [1 2 3 4 5]

After changing dst
dst: [10 2 3 4 5]
src: [1 2 3 4 5]

Length of dst less than src
Number Of Elements Copied: 4
dst: [1 2 3 4]
src: [1 2 3 4 5]

Length of dst less than src
Number Of Elements Copied: 5
dst: [1 2 3 4 5 0]
src: [1 2 3 4 5]

字串的複製函式

在 Go 中,字串只是一系列位元組。因此,將字串複製到位元組切片是合法的。

package main

import "fmt"

func main() {
    src := "abc"
    dst := make([]byte, 3)

    numberOfElementsCopied := copy(dst, src)
    fmt.Printf("Number Of Elements Copied: %d\n", numberOfElementsCopied)
    fmt.Printf("dst: %v\n", dst)
    fmt.Printf("src: %v\n", src)\
}

輸出

Number Of Elements Copied: 3
dst: [97 98 99]
src: abc

在使用複製函式時,源和目標也可以重疊。因此,可以從一個切片複製到自身。以下示例中,我們將切片的最後兩個元素複製到同一順序的前兩個元素中。

package main

import "fmt"

func main() {
    src := []int{1, 2, 3, 4, 5}
    numberOfElementsCopied := copy(src, src[3:])

    fmt.Printf("Number Of Elements Copied: %d\n", numberOfElementsCopied)
    fmt.Printf("src: %v\n", src)
}

輸出

Number Of Elements Copied: 2
src: [4 5 3 4 5]

結論

這就是 Go 中的複製函式。希望你喜歡這篇文章。

在 Go(Golang)中計算字串中子字串的例項

來源:golangbyexample.com/instances-substring-string-go/

目錄

  • 概述**

  • 程式碼:

概述

在 GO 中,字串採用 UTF-8 編碼。GO 的strings包提供了一個Count方法,可以用來獲取特定字串中非重疊子字串的數量。

以下是該函式的簽名

func Count(s, substr string) int

另外請注意,如果傳遞給函式的substr是一個空字串,則返回值將為 1 加上給定字串中的 Unicode 字元點數。

讓我們看一下工作程式碼

程式碼:

package main

import (
    "fmt"
    "strings"
)

func main() {

    //Case 1 Input string contains the substring
    res := strings.Count("abcdabcd", "ab")
    fmt.Println(res)

    //Case 1 Input string doesn't contains the substring
    res = strings.Count("abcdabcd", "xy")
    fmt.Println(res)

    //Case 1 Substring supplied is an empty string
    res = strings.Count("abcdabcd", "")
    fmt.Println(res)
}

輸出:

2
0
9
```*


<!--yml

類別:未分類

日期:2024-10-13 06:47:48

-->

# 計算數字序列可能解碼為字母的方式(Golang)

> 來源:[`golangbyexample.com/count-possible-decodings-digit-golang/`](https://golangbyexample.com/count-possible-decodings-digit-golang/)

目錄

+   概述

+   程式

## **概述**

假設我們有以下數字到字母的對映

```go
'A' -> "1"
'B' -> "2"
...
'Z' -> "26"

目標是計算給定數字序列的可能解碼數量

示例

Input: '15'
Output: 2

15 can be decoded as "AE" or "O"

程式

這裡是相應的程式。

package main

import (
	"fmt"
	"strconv"
)

func numDecodings(s string) int {

	runeArray := []rune(s)
	length := len(runeArray)
	if length == 0 {
		return 0
	}

	if string(runeArray[0]) == "0" {
		return 0
	}

	numwaysArray := make([]int, length)

	numwaysArray[0] = 1

	if length == 1 {
		return numwaysArray[0]
	}

	secondDigit := string(runeArray[0:2])
	num, _ := strconv.Atoi(secondDigit)
	if num > 10 && num <= 19 {
		numwaysArray[1] = 2
	} else if num > 20 && num <= 26 {
		numwaysArray[1] = 2
	} else if num == 10 || num == 20 {
		numwaysArray[1] = 1
	} else if num%10 == 0 {
		numwaysArray[1] = 0
	} else {
		numwaysArray[1] = 1
	}

	for i := 2; i < length; i++ {
		firstDigit := string(runeArray[i])
		if firstDigit != "0" {
			numwaysArray[i] = numwaysArray[i] + numwaysArray[i-1]
		}

		secondDigit := string(runeArray[i-1 : i+1])
		fmt.Println(i)
		fmt.Println(secondDigit)

		num, _ := strconv.Atoi(secondDigit)

		if num >= 10 && num <= 26 {
			numwaysArray[i] = numwaysArray[i] + numwaysArray[i-2]
		}
	}

	return numwaysArray[length-1]

}

func main() {
	output := numDecodings("15")
	fmt.Println(output)
}

輸出

2

注意: 請檢視我們的 Golang 高階教程。本系列教程詳盡,並且我們努力涵蓋所有概念及例項。本教程適合那些希望獲得專業知識和紮實理解 Golang 的人 - Golang 高階教程

如果你有興趣瞭解如何在 Golang 中實現所有設計模式,那麼這篇文章適合你 - 所有設計模式 Golang

在 Go (Golang) 中計數無防守單元格的程式

來源:golangbyexample.com/count-unguarded-cells-golang/

目錄

  • 概述

  • 程式

概述

給定兩個整數 m 和 n,表示一個 m*n 網格。除此之外,還給定兩個 2D 整數陣列

  • 守衛的位置為 guards[i] = [rowi , columni]。它表示第 i 個守衛的位置

  • 牆壁的位置為 guards[j] = [rowi , columni]。它表示第 i 個牆壁的位置

守衛可以向所有方向看

  • 西

除非被牆壁阻擋。守衛能看到的所有單元格都算作已防守。目標是找出無防守單元格的數量

這裡是相同的 leetcode 連結 – https://leetcode.com/problems/count-unguarded-cells-in-the-grid/

程式

以下是相同的程式

package main

import "fmt"

func countUnguarded(m int, n int, guards [][]int, walls [][]int) int {

	occupancy := make([][]int, m)

	for i := 0; i < m; i++ {
		occupancy[i] = make([]int, n)
	}

	for _, val := range guards {
		i := val[0]
		j := val[1]
		occupancy[i][j] = 2
	}

	for _, val := range walls {
		i := val[0]
		j := val[1]
		occupancy[i][j] = -1
	}

	for i := 0; i < m; i++ {
		for j := 0; j < n; j++ {
			if occupancy[i][j] == 2 {
				countUtil(i, j, m, n, &occupancy)
			}

		}
	}

	count := 0
	for i := 0; i < m; i++ {
		for j := 0; j < n; j++ {
			if occupancy[i][j] == 0 {
				count += 1
			}

		}
	}

	return count
}

func countUtil(x, y, m, n int, occupancy *([][]int)) {

	for i := x + 1; i < m; i++ {
		if (*occupancy)[i][y] == 0 {
			(*occupancy)[i][y] = 1
		}

		if (*occupancy)[i][y] == -1 || (*occupancy)[i][y] == 2 {
			break
		}
	}

	for i := x - 1; i >= 0; i-- {
		if (*occupancy)[i][y] == 0 {
			(*occupancy)[i][y] = 1
		}

		if (*occupancy)[i][y] == -1 || (*occupancy)[i][y] == 2 {
			break
		}
	}

	for i := y + 1; i < n; i++ {
		if (*occupancy)[x][i] == 0 {
			(*occupancy)[x][i] = 1
		}

		if (*occupancy)[x][i] == -1 || (*occupancy)[x][i] == 2 {
			break
		}
	}

	for i := y - 1; i >= 0; i-- {

		if (*occupancy)[x][i] == 0 {
			(*occupancy)[x][i] = 1
		}

		if (*occupancy)[x][i] == -1 || (*occupancy)[x][i] == 2 {
			break
		}
	}

}

func main() {
	output := countUnguarded(4, 6, [][]int{{0, 0}, {1, 1}, {2, 3}}, [][]int{{0, 1}, {2, 2}, {1, 4}})
	fmt.Println(output)

	output = countUnguarded(3, 3, [][]int{{1, 1}}, [][]int{{0, 1}, {1, 0}, {2, 1}, {1, 2}})
	fmt.Println(output)
}

輸出

7
4

注意:檢視我們的 Golang 高階教程。本系列教程內容詳盡,我們嘗試覆蓋所有概念並附有示例。本教程適合那些希望獲得專業知識和對 golang 有深入理解的人 – Golang 高階教程

如果你有興趣瞭解所有設計模式在 Golang 中如何實現。如果是,那麼這篇文章適合你 – 所有設計模式 Golang

此外,檢視我們的系統設計教程系列 – 系統設計教程系列

在 Go (Golang)中計算無向圖中無法到達的節點對

來源:golangbyexample.com/count-unreachable-pair-nodes-golang/

目錄

  • 概述

  • 程式

概述

給定一個整數 n。有 n 個節點編號為 0 到 n-1。還有一個二維整數陣列edges,其中edges[i] = [ai, bi]表示從 ai 到 bi 有一個無向節點。

目標是找到彼此無法到達的節點對數量

示例 1

n=3
edges=[{0,1}]

![](https://gitee.com/OpenDocCN/geekdoc-golang-zh/raw/master/docs/go-exam-2023/img/8473545ae2c070f9173a090845f5e532.png)

輸出

2

我們有兩個未連線的節點

[{0,2}, {1,2}]

示例 2

n=9
edges=[{0,1},{0,4},{0,5},{2,3},{2,6},{7,8}]

![](https://gitee.com/OpenDocCN/geekdoc-golang-zh/raw/master/docs/go-exam-2023/img/649eee1225b6dbfbb0bd449cfb524479.png)

輸出:

26

我們有 26 對未連線的節點

[{0,2}, {0,3}, {0,6}, {0,7}, {0,8},
{1,2}, {1,3}, {1,6}, {1,7}, {1,8},
{4,2}, {4,3}, {4,6}, {4,7}, {4,8},
{5,2}, {5,3}, {5,6}, {5,7}, {5,8},
{7,2}, {7,3}, {7,6},
{8,2}, {8,3}, {8,6}]

思路是從每個未訪問的節點開始進行深度優先搜尋,以識別每個連線圖中的節點數。在上面的例子中,每個連線圖中的節點數是

4
3
2

然後我們簡單地找到每個連線圖中的節點對數量

程式

以下是相應的程式

package main

import "fmt"

func countPairs(n int, edges [][]int) int64 {
	nodeMap := make(map[int][]int)

	for i := 0; i < len(edges); i++ {
		nodeMap[edges[i][0]] = append(nodeMap[edges[i][0]], edges[i][1])
		nodeMap[edges[i][1]] = append(nodeMap[edges[i][1]], edges[i][0])
	}

	visited := make(map[int]bool)

	var output int64
	var totalNodesVisited int64
	for i := 0; i < n; i++ {
		if !visited[i] {
			nodeVisited := visit(i, nodeMap, &visited)
			if totalNodesVisited != 0 {
				output += totalNodesVisited * nodeVisited
			}
			totalNodesVisited += nodeVisited
		}
	}
	return output
}

func visit(source_node int, nodeMap map[int][]int, visited *map[int]bool) int64 {
	(*visited)[source_node] = true

	var totalNodeVisited int64
	totalNodeVisited = 1
	neighbours, ok := nodeMap[source_node]
	if ok {
		for _, neighbour := range neighbours {
			if !(*visited)[neighbour] {
				nodeVisited := visit(neighbour, nodeMap, visited)
				totalNodeVisited += nodeVisited
			}
		}
	}

	return totalNodeVisited
}

func main() {

	n := 3
	edges := [][]int{{0, 1}}
	output := countPairs(n, edges)
	fmt.Println(output)

	n = 9
	edges = [][]int{{0, 1}, {0, 4}, {0, 5}, {2, 3}, {2, 6}, {7, 8}}
	output = countPairs(n, edges)
	fmt.Println(output)
}

輸出:

2
26

注意: 請檢視我們的 Golang 高階教程。本系列教程內容詳盡,努力覆蓋所有概念及示例。此教程適合希望獲得 Golang 專業知識和紮實理解的人 - Golang 高階教程

如果你有興趣瞭解如何在 Golang 中實現所有設計模式,那麼這篇文章適合你 - 所有設計模式 Golang

此外,請檢視我們的系統設計教程系列 - 系統設計教程系列

在 Go (Golang) 中建立目錄或資料夾

來源:golangbyexample.com/create-directory-folder-golang/

目錄

  • 概述

  • 程式碼

概述

os.Mkdir() 函式可以用於在 Go 中建立目錄或資料夾。

以下是該函式的簽名。

func Mkdir(name string, perm FileMode)

它接受兩個引數。

  • 第一個引數是命名目錄。如果命名目錄是一個完全合格的路徑,它將在該路徑下建立一個目錄。如果不是,它將相對於當前工作目錄建立一個目錄。

  • 第二個引數指定許可權位。資料夾或目錄是使用此許可權位建立的。

程式碼

package main

import (
    "log"
    "os"
)

func main() {
    //Create a folder/directory at a full qualified path
    err := os.Mkdir("/Users/temp", 0755)
    if err != nil {
        log.Fatal(err)
    }

    //Create a folder/directory at a full qualified path
    err = os.Mkdir("temp", 0755)
    if err != nil {
        log.Fatal(err)
    }
}

輸出

It will create a directory temp at location /Users location and at the current working directory location
  • 建立* 目錄* 資料夾* go* golang*

在 Go (Golang) 中建立一個新時間例項

來源:golangbyexample.com/create-new-time-instance-go/

在 Go 中,time.Time 結構用於表示時間或日期的例項。下面是建立新時間例項的三種方法

目錄

** 使用 time.Now()")

  • 使用 time.Date()")

  • 使用 time.Parse()")

使用 time.Now()

time.Now() 函式可用於獲取當前本地時間戳。該函式的簽名是

func Now() Time

使用 time.Date()

time.Date() 函式接受年份、月份、日期、小時、分鐘、秒、納秒和位置,並返回一個時間格式為 yyyy-mm-dd hh:mm:ss + nsec,具有與給定位置相對應的適當時區。該函式的簽名是

func Date(year int, month Month, day, hour, min, sec, nsec int, loc *Location) Time

使用 time.Parse()

time.Parse() 可用於將時間的字串表示轉換為 time.Time 例項。該函式的簽名是

func Parse(layout, value string) (Time, error)

time.Parse 函式接受兩個引數 –

  • 第一個引數是包含時間格式佔位符的佈局

  • 第二個引數是表示時間的實際格式化字串。

下面是一個演示上述三種方法的工作程式碼示例

package main

import (
    "fmt"
    "time"
)

func main() {
    //time.Now() example
    t := time.Now()
    fmt.Println(t)

    //time.Date() Example
    t = time.Date(2021, time.Month(2), 21, 1, 10, 30, 0, time.UTC)
    fmt.Println(t)

    //time.Parse() Example
    //Parse YYYY-MM-DD
    t, _ = time.Parse("2006-01-02", "2020-01-29")
    fmt.Println(t)
}

輸出:

2020-02-03 11:34:10.85639 +0530 IST m=+0.000297951
2021-02-21 01:10:30 +0000 UTC
2020-01-29 00:00:00 +0000 UTC
  • golang*

在 Go(Golang)中建立一個空檔案。

來源:golangbyexample.com/create-empty-file-go/

目錄

  • 概述

  • 程式碼:

概述

os.Create() 可用於在 Go 中建立一個空檔案。該函式的簽名為

func Create(name string) (*File, error) 

基本上這個函式

  • 建立一個模式為 0666 的命名檔案。

  • 如果檔案已經存在,它將截斷該檔案。

  • 如果路徑有問題,它將返回一個路徑錯誤。

  • 它返回一個檔案描述符,可用於讀取和寫入。

程式碼:

package main

import (
    "log"
    "os"
)

func main() {
    file, err := os.Create("emptyFile.txt")
    if err != nil {
        log.Fatal(err)
    }
    defer file.Close()
}

輸出

Check the contents of the file. It will be empty
  • 空檔案* 檔案*

在 Go (Golang)中建立字串的重複副本

來源:golangbyexample.com/create-count-repeating-copies-string-golang/

目錄

  • 概述**

  • 程式碼:

概述

GO 的strings包提供了一個Repeat方法,可用於建立給定字串的重複副本。它的輸入為重複次數。

以下是函式的簽名。它返回字串的副本。

func Repeat(s string, count int) string

讓我們看看有效的程式碼

程式碼:

package main

import (
    "fmt"
    "strings"
)

func main() {
    res := strings.Repeat("abc", 4)
    fmt.Println(res)
}

輸出:

abcabcabcabc

在 Go(Golang)中建立/初始化/宣告 map

來源:golangbyexample.com/create-map-golang/

目錄

  • 概述

  • 宣告一個 Map

  • 建立一個 Map

    • 使用 map[<key_type>]<value_type>格式

    • 使用 Make

概述

map 是 Golang 內建的資料型別,類似於雜湊表,它將鍵對映到值。

下面是 map 的格式:

map[key_type]value_type

key_typevalue_type可以是不同型別或相同型別。在下面的例子中,鍵型別是string,值型別是int

map[string]int

宣告一個 Map

map 也可以使用 var 關鍵字宣告,但它會建立一個 nil map,因為 map 的預設零值是 nil。向該 map 新增任何鍵值對將導致恐慌。讓我們看看這個例子

package main

func main() {
    var employeeSalary map[string]int
    employeeSalary["Tom"] = 2000
}

輸出

panic: assignment to entry in nil map

上面的程式因 map 為 nil 而導致恐慌。

使用var關鍵字宣告 map 的一個用例是當需要將一個已存在的 map 賦值給它或當我們想要賦值函式的結果時。

建立一個 Map

建立 map 的兩種方式

  • 使用 map[<key_type>]<value_type>{}格式也稱為 map 字面量

  • 使用 make

讓我們逐一看看上述每種方法。

使用 map[<key_type>]<value_type>格式

建立 map 的最常見方式之一是使用 map 字面量:

map[key_type]value_type{}

上述例子的鍵型別是字串,值型別是整數

employeeSalary := map[string]int{}

map 也可以建立並初始化一些鍵值

employeeSalary := map[string]int{
"John": 1000
"Sam": 2000
}

也可以向 map 中新增鍵值對

employeeSalary["Tom"] = 2000

讓我們看看一個程式

package main

import "fmt"

func main() {
    //Declare
    employeeSalary := map[string]int{}
    fmt.Println(employeeSalary)

    //Intialize using map lieteral
    employeeSalary = map[string]int{
        "John": 1000,
        "Sam":  1200,
    }

    //Adding a key value
    employeeSalary["Tom"] = 2000
    fmt.Println(employeeSalary)
}

輸出

map[]
map[John:1000 Sam:1200 Tom:2000]

在上面的程式中,我們建立了一個初始化為某些值的 map 字面量。然後我們在其中新增了另一個鍵值對。接著我們使用fmt.Println列印它,以格式 map[key:value key:value]列印所有的鍵值對。

使用 Make

這是建立 map 的另一種方式。內建函式make可用於建立 map。它返回一個初始化的 map。因此可以向其中新增鍵值對。

package main

import "fmt"

func main() {
    //Declare
    employeeSalary := make(map[string]int)
    //Adding a key value
    employeeSalary["Tom"] = 2000
    fmt.Println(employeeSalary)
}

輸出

map[Tom:2000]

在上面的程式中,我們使用 make 函式建立了一個 map。然後我們在其中新增了一個鍵值對。接著我們使用fmt.Println列印它,列印出所有的鍵值對。

在 Go (Golang)中建立或初始化一個新字串

來源:golangbyexample.com/create-string-golang/

目錄

** 概覽

  • 程式

概覽

下面是一種簡單的方法來初始化或建立一個 Go 中的字串。在下面的程式中,我們簡單地宣告並定義了一個名為sample的字串。

注意語法

sample := "test"

這是完整的程式

程式

package main

import "fmt"

func main() {
	sample := "test"
	fmt.Println(sample)
}

輸出

test

如果我們只想宣告一個字串變數,下面就是方法。宣告的字串會初始化為空字串。

package main

import "fmt"

func main() {
    var sample string
    fmt.Println(sample)
}

輸出

注意: 請檢視我們的 Golang 高階教程。本系列教程內容詳盡,我們嘗試覆蓋所有概念及示例。此教程適合希望獲得專業知識和紮實理解 Golang 的人士 – Golang 高階教程

如果你有興趣瞭解所有設計模式如何在 Golang 中實現。如果是,那麼這篇文章就是為你準備的 –

所有設計模式 Golang

注意: 請檢視我們的系統設計教程系列 系統設計問題*

透過在 Go (Golang) 中呼叫恐慌函式建立恐慌

來源:golangbyexample.com/create-panic-golang/

目錄

  • 概述

  • 示例

概述

Go 提供了一個特殊函式來建立恐慌。下面是該函式的語法

func panic(v interface{})

此函式可以由程式設計師顯式呼叫以建立恐慌。它接受一個空介面作為引數。

在程式設計師可以顯式呼叫恐慌函式的一些情況包括:

  • 函式期望一個有效的引數,但卻提供了一個 nil 引數。在這種情況下,程式無法繼續,並且會因傳入 nil 引數而引發恐慌。

  • 程式無法繼續的任何其他情況。

示例

讓我們看一個例子

package main

import "fmt"

func main() {

	a := []string{"a", "b"}
	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])
}

輸出

panic: runtime error: index out of range [2] with length 2

goroutine 1 [running]:
main.checkAndPrint(0xc00009af58, 0x2, 0x2, 0x2)
        main.go:15 +0x31
main.main()
        main.go:8 +0x7d
exit status 2

在上面的程式中,我們再次有一個函式 checkAndPrint,它接受一個切片作為引數和一個索引。然後它檢查傳入的索引是否大於切片長度減去 1。如果是,那麼它就是超出切片邊界的訪問,因此會引發恐慌。如果不是,則列印該索引處的值。再注意輸出中有兩件事

  • 錯誤資訊

  • 發生恐慌時的堆疊跟蹤

在 Go (Golang)中建立浮點切片或陣列。

來源:golangbyexample.com/slice-array-floats-golang/

目錄。

** 概述

  • 浮點切片

  • 浮點陣列

概述

在 Golang 中也可以建立浮點資料型別的切片或陣列。實際上,任何資料型別都可以在 Go 中建立切片或陣列。本教程包含建立浮點資料型別切片或陣列的簡單示例。

在此補充說明,Golang 中的陣列大小是固定的,而切片可以具有可變大小。更多詳情請見這裡。

陣列 – golangbyexample.com/understanding-array-golang-complete-guide/

切片 – golangbyexample.com/slice-in-golang/

浮點切片

package main

import "fmt"

func main() {

	//First Way
	var floats_first []float64
	floats_first = append(floats_first, 1.1)
	floats_first = append(floats_first, 2.2)
	floats_first = append(floats_first, 3.3)

	fmt.Println("Output for First slice of floats")
	for _, c := range floats_first {
		fmt.Println(c)
	}

	//Second Way
	floats_second := make([]float64, 3)
	floats_second[0] = 3.3
	floats_second[1] = 2.2
	floats_second[2] = 1.1

	fmt.Println("\nOutput for Second slice of floats")
	for _, c := range floats_second {
		fmt.Println(c)
	}
}

輸出

Output for First slice of floats
1.1
2.2
3.3

Output for Second slice of floats
3.3
2.2
1.1

我們有兩種建立浮點切片的方法。第一種方法是

var floats_first []float64
floats_first = append(floats_first, 1.1)
floats_first = append(floats_first, 2.2)
floats_first = append(floats_first, 3.3)

在第二種方法中,我們使用 make 命令來建立浮點切片。

floats_second := make([]float64, 3)
floats_second[0] = 3.3
floats_second[1] = 2.2
floats_second[2] = 1.1

浮點陣列

package main

import "fmt"

func main() {

	var floats_first [3]float64

	floats_first[0] = 1.1
	floats_first[1] = 2.2
	floats_first[2] = 3.3

	fmt.Println("Output for First Array of floats")
	for _, c := range floats_first {
		fmt.Println(c)
	}

	floats_second := [3]float64{
		3.3,
		2.2,
		1.1,
	}

	fmt.Println("\nOutput for Second Array of floats")
	for _, c := range floats_second {
		fmt.Println(c)
	}
}

輸出

Output for First Array of floats
1.1
2.2
3.3

Output for Second Array of floats
3.3
2.2
1.1

我們有兩種建立陣列的方法。第一種方法是

var floats_first [3]float64
floats_first[0] = 1.1
floats_first[1] = 2.2
floats_first[2] = 3.3

在第二種方法中,我們直接用建立的浮點數初始化陣列。

floats_second := [3]float64{
	3.3,
	2.2,
	1.1,
}

請檢視我們的 Golang 高階教程。本系列教程內容詳盡,我們盡力涵蓋所有概念和示例。本教程適合希望獲得專業知識和對 Golang 有深入理解的讀者 – Golang 高階教程

如果您有興趣瞭解如何在 Golang 中實現所有設計模式。如果是的話,這篇文章適合您 – 所有設計模式 Golang

在 Go 中建立整數的切片或陣列(Golang)

來源:golangbyexample.com/slice-array-integers-golang/

目錄

  • 概述**

  • 整數切片

  • 整數陣列

概述

在 Golang 中也可以建立int資料型別的切片或陣列。實際上,Go 中可以建立任何資料型別的切片或陣列。本教程包含簡單的示例,演示如何在 Golang 中建立 int 資料型別的切片或陣列。

這裡補充一下,在 Golang 中陣列是固定大小的,而切片可以有可變大小。更多細節在這裡

陣列 – golangbyexample.com/understanding-array-golang-complete-guide/

切片 – golangbyexample.com/slice-in-golang/

整數切片

package main

import "fmt"

func main() {

	//First Way
	var integers_first []int
	integers_first = append(integers_first, 1)
	integers_first = append(integers_first, 2)
	integers_first = append(integers_first, 3)

	fmt.Println("Output for First slice of integers")
	for _, c := range integers_first {
		fmt.Println(c)
	}

	//Second Way
	integers_second := make([]int, 3)
	integers_second[0] = 3
	integers_second[1] = 2
	integers_second[2] = 1

	fmt.Println("\nOutput for Second slice of integers")
	for _, c := range integers_second {
		fmt.Println(c)
	}
}

輸出

Output for First slice of integers
1
2
3

Output for Second slice of integers
3
2
1

我們有兩種建立整數切片的方法。第一種方法是

var integers_first []int
integers_first = append(integers_first, 1)
integers_first = append(integers_first, 2)
integers_first = append(integers_first, 3)

在第二種方法中,我們使用 make 命令來建立整數切片

integers_second := make([]int, 3)
integers_second[0] = 3
integers_second[1] = 2
integers_second[2] = 1

無論哪種方法都可以。這就是我們如何建立整數切片

整數陣列

package main

import "fmt"

func main() {

	var integers_first [3]int

	integers_first[0] = 1
	integers_first[1] = 2
	integers_first[2] = 3

	fmt.Println("Output for First Array of integers")
	for _, c := range integers_first {
		fmt.Println(c)
	}

	integers_second := [3]int{
		3,
		2,
		1,
	}

	fmt.Println("\nOutput for Second Array of integers")
	for _, c := range integers_second {
		fmt.Println(c)
	}
}

輸出

Output for First Array of integers
1
2
3

Output for Second Array of integers
3
2
1

我們有兩種建立陣列的方法。第一種方法是

var integers_first [3]int
integers_first[0] = 1
integers_first[1] = 2
integers_first[2] = 3

在第二種方法中,我們直接用建立的整數初始化陣列

integers_second := [3]int{
	3,
	2,
	1,
}

檢視我們的 Golang 高階教程。本系列教程詳盡,我們努力覆蓋所有概念及示例。本教程適合那些希望獲得專業知識和紮實理解 Golang 的人 – Golang 高階教程

如果你有興趣瞭解所有設計模式如何在 Golang 中實現。如果是的話,這篇文章適合你 –所有設計模式 Golang

在 Go (Golang)中建立字串切片或陣列

來源:golangbyexample.com/slice-array-string-golang/

目錄

  • 概述

  • 字串切片

  • 字串陣列

概述

在 Golang 中,也可以建立string資料型別的切片或陣列。實際上,Go 中可以建立任何資料型別的切片或陣列。本教程包含建立string資料型別的切片或陣列的簡單示例。

這裡補充一下,在 golang 中,陣列是固定大小的,而切片可以有可變大小。更多詳細資訊請檢視這裡。

陣列 – golangbyexample.com/understanding-array-golang-complete-guide/

切片 – golangbyexample.com/slice-in-golang/

字串切片

package main

import "fmt"

func main() {

	//First Way
	var string_first []string
	string_first = append(string_first, "abc")
	string_first = append(string_first, "def")
	string_first = append(string_first, "ghi")

	fmt.Println("Output for First slice of string")
	for _, c := range string_first {
		fmt.Println(c)
	}

	//Second Way
	string_second := make([]string, 3)
	string_second[0] = "ghi"
	string_second[1] = "def"
	string_second[2] = "abc"

	fmt.Println("\nOutput for Second slice of string")
	for _, c := range string_second {
		fmt.Println(c)
	}
}

輸出

Output for First slice of string
abc
def
ghi

Output for Second slice of string
ghi
def
abc

我們有兩種建立字串切片的方法。第一種方法是

var string_first []string
string_first = append(string_first, "abc")
string_first = append(string_first, "def")
string_first = append(string_first, "ghi")

在第二種方法中,我們使用 make 命令來建立字串切片。

string_second := make([]string, 3)
string_second[0] = "ghi"
string_second[1] = "def"
string_second[2] = "abc"

無論哪種方式都可以。這是我們建立字串切片的方法。

字串陣列

package main

import "fmt"

func main() {

	var string_first [3]string

	string_first[0] = "abc"
	string_first[1] = "def"
	string_first[2] = "ghi"

	fmt.Println("Output for First Array of string")
	for _, c := range string_first {
		fmt.Println(c)
	}

	string_second := [3]string{
		"ghi",
		"def",
		"abc",
	}

	fmt.Println("\nOutput for Second Array of string")
	for _, c := range string_second {
		fmt.Println(c)
	}
}

輸出

Output for First Array of string
abc
def
ghi

Output for Second Array of string
ghi
def
abc

我們有兩種建立陣列的方法。第一種方法是

var string_first [3]string
string_first[0] = "abc"
string_first[1] = "def"
string_first[2] = "ghi"

在第二種方法中,我們直接用一些字串初始化陣列。

string_second := [3]string{
	"ghi",
	"def",
	"abc",
}

檢視我們的 Golang 高階教程。本系列的教程內容詳盡,盡力涵蓋所有概念及示例。本教程適合那些希望掌握 golang 並深入理解的讀者 – Golang 高階教程

如果你有興趣瞭解所有設計模式如何在 Golang 中實現。如果是的話,這篇文章就是為你準備的 – 所有設計模式 Golang

在 Go (Golang) 中的數字立方根

來源:golangbyexample.com/cube-root-number-golang/

目錄

  • 概述

  • 程式碼:

概述

GO 的 math 包提供了一個 Cbrt 方法,可以用於獲取該數字的立方根。

以下是該函式的簽名。它接受一個浮點數作為輸入,並返回一個浮點數。

func Cbrt(x float64) float64

Cbrt 函式的一些特殊情況是

  • Cbrt(±0) = ±0

  • Cbrt(±Inf) = ±Inf

  • Cbrt(NaN) = NaN

程式碼:

package main

import (
    "fmt"
    "math"
)

func main() {
    res := math.Cbrt(8)
    fmt.Println(res)

    res = math.Cbrt(27)
    fmt.Println(res)

    res = math.Cbrt(30.33)
    fmt.Println(res)
}

輸出:

2
3
3.118584170228812
  • 立方根* go* 數字*

Go 語言中的當前時間戳

來源:golangbyexample.com/current-timestamp-in-golang/

目錄

概述

  • 程式碼

概述

在本教程中,我們將看到如何使用 Go 語言中的 time 包獲取當前時間戳。當前時間可以用不同的方式表示。

  • time.Time物件
t := time.Now() //It will return time.Time object with current timestamp
  • Unix 時間(也稱為紀元時間) – 它是自 1970 年 1 月 1 日 00:00:00 UTC 以來經過的秒數。這個時間也被稱為 Unix 紀元。
t := time.Now().Unix() 
//Will return number of seconds passed since Unix epoch
  • Unix 納秒 – 自 1970 年 1 月 1 日 00:00:00 UTC 以來經過的納秒數
t := time.Now().UnixNano() 
//Will return number of nano seconds passed since Unix epoch
  • Unix 毫秒 – 自 1970 年 1 月 1 日 00:00:00 UTC 以來經過的毫秒數
t:= int64(time.Nanosecond) * t.UnixNano() / int64(time.Millisecond)/ time.Millisecond  
//Number of millisecond elapsed since Unix epoch
  • Unix 微秒 – 自 1970 年 1 月 1 日 00:00:00 UTC 以來經過的微秒數
t:= int64(time.Nanosecond) * t.UnixNano() / int64(time.Millisecond)/ time.Millisecond  
//Number of millisecond elapsed since Unix epoch

程式碼

package main

import (
    "fmt"
    "time"
)

func main() {
    t := time.Now() //It will return time.Time object with current timestamp
    fmt.Printf("time.Time %s\n", t)

    tUnix := t.Unix()
    fmt.Printf("timeUnix: %d\n", tUnix)

    tUnixNano := t.UnixNano()
    fmt.Printf("timeUnixNano: %d\n", tUnixNano)

    tUnixMilli := int64(time.Nanosecond) * t.UnixNano() / int64(time.Millisecond)
    fmt.Printf("timeUnixMilli: %d\n", tUnixMilli)

    tUnixMicro := int64(time.Nanosecond) * t.UnixNano() / int64(time.Microsecond)
    fmt.Printf("timeUnixMicro: %d\n", tUnixMicro)
}

輸出:

time.Time 2020-01-24 09:43:42.196901 UTC m=+0.000229700
timeUnix: 1579839222
timeUnixNano: 1579839222196901000
timeUnixMilli: 1579839222196
timeUnixMicro: 1579839222196901
  • 紀元* 毫秒* 納秒* unix*

Go (Golang) 中的 defer 中的自定義函式

來源:golangbyexample.com/custom-function-defer-golang/

目錄

  • 概述

  • 示例

概述

我們也可以在 defer 中呼叫自定義函式。讓我們來看一個示例

示例

package main
import "fmt"
func main() {
    defer test()
    fmt.Println("Executed in main")
}
func test() {
    fmt.Println("In Defer")
}

輸出

Executed in main
In Defer

在上述程式中,有一個defer語句呼叫了名為test的自定義函式。從輸出可以看到,test函式在主函式中的所有操作執行完畢後被呼叫,並在主函式返回之前呼叫。這就是為什麼

Executed in main

會在之前列印

In Defer

上述函式還顯示在主函式中使用 defer 是完全可以的。

Go 中的日期 (Golang)

來源:golangbyexample.com/date-in-golang/

在 Go 中,日期僅透過 time.Time 結構表示。Go 中沒有單獨的 Date 結構。可以使用 time.Date 函式構造日期。該函式返回格式為 yyyy-mm-dd hh:mm:ss + nsec 的時間,包含與給定位置對應的適當時區。函式的簽名是:

func Date(year int, month Month, day, hour, min, sec, nsec int, loc *Location) Time

從簽名中可以看出,函式的引數是

  • 小時

  • 毫秒

  • 位置

關於 time.Date 函式的一些注意事項

  • 如果傳入的位置資訊為 nil,Date 函式將會引發 panic。

  • 月、日、時、分、秒、納秒值會被規範化。因此,如果傳入的月份是 14,它將被轉換為 2。

讓我們看看一個工作示例:

package main

import (
    "fmt"
    "time"
)

func main() {
    t := time.Date(2021, time.Month(2), 21, 1, 10, 30, 0, time.UTC)
    fmt.Println(t)
}

輸出:

2021-02-21 01:10:30 +0000 UTC

在 Go(Golang)中宣告/初始化/建立陣列或切片

來源:golangbyexample.com/declare-initialize-create-array-slice-golang/

目錄

概述

  • 建立切片

    • 使用 []<型別>{} 格式

    • 從另一個切片或陣列建立切片

      • 從陣列建立切片

      • 從切片建立切片

    • 使用 make 函式

    • 使用新函式

  • 建立陣列 *# 概述

與其他程式語言類似,Golang 也有陣列資料結構。但在 Go 中,陣列的行為與其他語言略有不同,我們還有一種叫切片的結構,它類似於陣列的引用。切片比陣列更強大且更方便使用。事實上,切片在其他程式語言中更類似於陣列。

在這篇文章中,我們將學習如何

  • 建立切片例項

  • 建立陣列例項

建立切片

建立切片的方式有四種

  • 使用 []<型別>{} 格式

  • 從另一個切片或陣列建立切片

  • 使用 make

  • 使用新方法

讓我們逐一檢視上述每種方法。

使用 []<型別>{} 格式

宣告切片的最常見方式是這樣的

s := []int

它宣告瞭一個長度為 0、容量為 0 的空切片。我們也可以在宣告時初始化切片。

s := []int{1,2}

它宣告瞭一個長度為 2、容量也為 2 的整數切片。容量等於實際指定的切片元素數量。我們還有兩個由 Go 提供的庫函式可以用來獲取切片的 長度容量

  • len() 函式 – 用於切片的長度

  • cap() 函式 – 用於切片的容量

讓我們看看一個小程式,展示以上幾點。

package main

import "fmt"

func main() {
    sample := []int{}
    fmt.Println(len(sample))
    fmt.Println(cap(sample))
    fmt.Println(sample)

    letters := []string{"a", "b", "c"}
    fmt.Println(len(letters))
    fmt.Println(cap(letters))
    fmt.Println(letters)
}

輸出

0
0
[]

3
3
[a b c]

當實際元素未指定時,切片的長度和容量均為零。當指定實際元素時,長度和容量等於指定的實際元素數量。

從另一個切片或陣列建立切片

切片可以透過重新切片現有切片或陣列來建立。

從陣列建立切片

透過重新切片現有陣列建立新切片的格式為

[n]sample[start:end]

上述操作將返回一個新切片,從陣列的索引 start 開始到索引 end-1。因此,索引 end 的元素不包含在新建立的切片中。在重新切片時,起始和結束索引都是可選的。

  • 起始索引的預設值為零

  • 結束索引的預設值是陣列的長度。

讓我們看看一個例子。

package main

import "fmt"

func main() {
    numbers := [5]int{1, 2, 3, 4, 5}

    //Both start and end
    num1 := numbers[2:4]
    fmt.Println("Both start and end")
    fmt.Printf("num1=%v\n", num1)
    fmt.Printf("length=%d\n", len(num1))
    fmt.Printf("capacity=%d\n", cap(num1))

    //Only start
    num2 := numbers[2:]
    fmt.Println("\nOnly start")
    fmt.Printf("num1=%v\n", num2)
    fmt.Printf("length=%d\n", len(num2))
    fmt.Printf("capacity=%d\n", cap(num2))

    //Only end
    num3 := numbers[:3]
    fmt.Println("\nOnly end")
    fmt.Printf("num1=%v\n", num3)
    fmt.Printf("length=%d\n", len(num3))
    fmt.Printf("capacity=%d\n", cap(num3))

    //None
    num4 := numbers[:]
    fmt.Println("\nOnly end")
    fmt.Printf("num1=%v\n", num4)
    fmt.Printf("length=%d\n", len(num4))
    fmt.Printf("capacity=%d\n", cap(num4))
}

輸出

Both start and end
num1=[3 4]
length=2
capacity=3

Only start
num1=[3 4 5]
length=3
capacity=3

Only end
num1=[1 2 3]
length=3
capacity=5

Only end
num1=[1 2 3 4 5]
length=5
capacity=5

請注意上面的例子中:

  • 新建立切片的長度 = (endstart)

  • 新建立切片的容量 = (length_of_arraystart)

num1切片的樣子如下。

![](https://gitee.com/OpenDocCN/geekdoc-golang-zh/raw/master/docs/go-exam-2023/img/33586fc71a4b7b6f0294dc7dc24f41df.png)

新建立的切片仍然引用原始陣列。要檢查這一點,可以在陣列的任意索引處更改元素,然後重新列印切片。

numbers[3] = 8
fmt.Printf("num1=%v\n", num2)
fmt.Printf("num3=%v\n", num3)
fmt.Printf("num4=%v\n", num4)

輸出如下:

num1=[3 8 5]
num3=[1 2 3 8]
num4=[1 2 3 8 5]

這證明每個新切片仍然引用原始陣列。

從切片建立切片

我們關於從陣列重新切片的討論同樣適用於這裡。請參見下面的例子以說明同樣的內容。

package main

import "fmt"

func main() {
    numbers := []int{1, 2, 3, 4, 5}

    //Both start and end
    num1 := numbers[2:4]
    fmt.Println("Both start and end")
    fmt.Printf("num1=%v\n", num1)
    fmt.Printf("length=%d\n", len(num1))
    fmt.Printf("capacity=%d\n", cap(num1))

    //Only start
    num2 := numbers[2:]
    fmt.Println("\nOnly start")
    fmt.Printf("num1=%v\n", num2)
    fmt.Printf("length=%d\n", len(num2))
    fmt.Printf("capacity=%d\n", cap(num2))

    //Only end
    num3 := numbers[:3]
    fmt.Println("\nOnly end")
    fmt.Printf("num1=%v\n", num3)
    fmt.Printf("length=%d\n", len(num3))
    fmt.Printf("capacity=%d\n", cap(num3))

    //None
    num4 := numbers[:]
    fmt.Println("\nOnly end")
    fmt.Printf("num1=%v\n", num4)
    fmt.Printf("length=%d\n", len(num4))
    fmt.Printf("capacity=%d\n", cap(num4))
}

輸出

Both start and end
num1=[3 4]
length=2
capacity=3

Only start
num1=[3 4 5]
length=3
capacity=3

Only end
num1=[1 2 3]
length=3
capacity=5

Only end
num1=[1 2 3 4 5]
length=5
capacity=5

在這裡,新建立的切片也引用與原始切片所引用的相同基礎陣列。要檢查這一點,可以在原始切片的任意索引處更改元素,然後重新列印所有新建立的切片。

numbers[3] = 8
fmt.Printf("num1=%v\n", num2)
fmt.Printf("num3=%v\n", num3)
fmt.Printf("num4=%v\n", num4)

使用 make 函式

make是 Go 提供的一個內建函式,也可以用來建立切片。以下是 make 函式的簽名。

func make([]{type}, length, capacity int) []{type}

建立切片時,make函式的容量是一個可選引數。當省略容量時,切片的容量等於指定的長度。使用make函式時,Go 背後會分配一個與容量相等的陣列。分配的陣列的所有元素都初始化為該型別的預設零值。讓我們看看一個說明這一點的程式。

package main

import "fmt"

func main() {
    numbers := make([]int, 3, 5)
    fmt.Printf("numbers=%v\n", numbers)
    fmt.Printf("length=%d\n", len(numbers))
    fmt.Printf("capacity=%d\n", cap(numbers))

    //With capacity ommited
    numbers = make([]int, 3)
    fmt.Println("\nCapacity Ommited")
    fmt.Printf("numbers=%v\n", numbers)
    fmt.Printf("length=%d\n", len(numbers))
    fmt.Printf("capacity=%d\n", cap(numbers))
}

輸出

numbers=[0 0 0]
length=3
capacity=5

With Capacity Ommited
numbers=[0 0 0]
length=3
capacity=3

使用 new 函式

new是 Go 提供的一個內建函式,也可以用來建立切片。這種建立切片的方式並不常用,因為make在功能上更加靈活。一般情況下不常使用,並且使用new函式會返回指向 nil 切片的指標。讓我們看一個例子。在下面的例子中,我們使用解引用運算子‘*’,因為new函式返回指向 nil 切片的指標。

package main

import "fmt"

func main() {
    numbers := new([]int)
    fmt.Printf("numbers=%v\n", *numbers)
    fmt.Printf("length=%d\n", len(*numbers))
    fmt.Printf("capacity=%d\n", cap(*numbers))
}

輸出

numbers=[]
length=0
capacity=0

建立一個陣列

陣列宣告中的元素數量和實際元素都是可選的。

在下面的例子中,我們看到建立陣列的 4 種方式。

  • 同時指定陣列的長度和實際元素。例如:
[2]int{1, 2}
  • 僅長度——在這種情況下,所有實際元素都填充為該型別的預設值零。例如:
[2]int{}
  • 僅實際元素——在這種情況下,陣列的長度將等於實際元素的數量。符號‘…’在不指定長度時需要在方括號內使用,例如[…]。該符號是指令,指示編譯器計算長度。
[...]int{2, 3}
  • 沒有長度和實際元素——在這種情況下,將建立一個空陣列。與上述相似,符號‘…’在這種情況下也需要使用。
[...]int{}

讓我們看一個程式碼示例來說明上述要點。還請記住,可以使用內建函式len()來計算陣列的長度。在下面的程式中,我們使用len()函式來計算陣列的長度。

package main

import "fmt"

func main() {
    //Both number of elements and actual elements
    sample1 := [2]int{1, 2}
    fmt.Printf("Sample1: Len: %d, %v\n", len(sample1), sample1)

    //Only actual elements
    sample2 := [...]int{2, 3}
    fmt.Printf("Sample2: Len: %d, %v\n", len(sample2), sample2)

    //Only number of elements
    sample3 := [2]int{}
    fmt.Printf("Sample3: Len: %d, %v\n", len(sample3), sample3)

    //Without both number of elements and actual elements
    sample4 := [...]int{}
    fmt.Printf("Sample4: Len: %d, %v\n", len(sample4), sample4)
}

輸出

Sample1: Len: 2, [1 2]
Sample2: Len: 2, [2 3]
Sample3: Len: 2, [0 0]
Sample4: Len: 0, []

請注意,上述示例中,對於sample3變數,實際元素用預設值 0 填充。

如果指定的實際元素少於陣列的長度也是可以的。其餘元素將用指定型別的預設值填充。請參見下面的示例。指定的陣列長度為 4,而只有 2 個實際元素被宣告。因此,剩餘的兩個元素被賦值為 0,這是int的預設零值。

package main

import "fmt"

func main() {
    sample := [4]int{5, 8}
    fmt.Printf("Sample: Len: %d, %v\n", len(sample), sample)
}

輸出

Sample: Len: 4, [5 8 0 0]

相關文章