透過示例學習-Go-語言-2023-二十-

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

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

Golang 中的迭代器設計模式

來源:golangbyexample.com/go-iterator-design-pattern/

注意:如有興趣瞭解其他設計模式如何在 GO 中實現,請檢視此完整參考 – Go 中的所有設計模式 (Golang)

目錄

** 介紹:

  • UML 圖:

  • 對映

  • 示例

  • 完整工作程式碼:

介紹:

迭代器設計模式是一種行為設計模式。在此模式中,集合結構提供一個迭代器,讓其能夠順序遍歷集合結構中的每個元素,而不暴露其底層實現。

以下是迭代器設計模式的基本元件。

  • 迭代器 介面:該介面提供基本操作,如hasNext()getNext()等。這些操作顧名思義可以讓你遍歷集合、重新開始迭代等。

  • 集合介面:該介面表示需要遍歷的集合。該介面定義了一個方法createIterator(),返回迭代器型別。

  • 具體迭代器:迭代器介面的具體實現。

  • 具體集合:集合介面的具體實現。

此模式的主要思想是將集合結構的迭代邏輯暴露到一個不同的物件中(該物件實現了迭代器介面)。此迭代器提供了一種獨立於型別的遍歷集合的通用方法。

UML 圖:

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

對映

以下表格表示 UML 圖中參與者到實際實現參與者的對映,位於“示例”中。

集合 collection.go
具體集合 userCollection.go
迭代器 mac.go
具體迭代器 1 userIterator.go
客戶端 main.go

示例

collection.go

package main

type collection interface {
    createIterator() iterator
}

userCollection.go

package main

type userCollection struct {
    users []*user
}

func (u *userCollection) createIterator() iterator {
    return &userIterator{
        users: u.users,
    }
}

iterator.go

package main

type iterator interface {
    hasNext() bool
    getNext() *user
}

userIterator.go

package main

type userIterator struct {
    index int
    users []*user
}

func (u *userIterator) hasNext() bool {
    if u.index < len(u.users) {
        return true
    }
    return false
}

func (u *userIterator) getNext() *user {
    if u.hasNext() {
        user := u.users[u.index]
        u.index++
        return user
    }
    return nil
}

user.go

package main

type user struct {
    name string
    age  int
}

main.go

package main

import "fmt"

func main() {
    user1 := &user{
        name: "a",
        age:  30,
    }
    user2 := &user{
        name: "b",
        age:  20,
    }
    userCollection := &userCollection{
        users: []*user{user1, user2},
    }
    iterator := userCollection.createIterator()
    for iterator.hasNext() {
        user := iterator.getNext()
        fmt.Printf("User is %+v\n", user)
    }
}

輸出:

User is &{name:a age:30}
User is &{name:b age:20}

完整工作程式碼:

package main

import "fmt"

type collection interface {
    createIterator() iterator
}

type userCollection struct {
    users []*user
}

func (u *userCollection) createIterator() iterator {
    return &userIterator{
        users: u.users,
    }
}

type iterator interface {
    hasNext() bool
    getNext() *user
}

type userIterator struct {
    index int
    users []*user
}

func (u *userIterator) hasNext() bool {
    if u.index < len(u.users) {
        return true
    }
    return false
}

func (u *userIterator) getNext() *user {
    if u.hasNext() {
        user := u.users[u.index]
        u.index++
        return user
    }
    return nil
}

type user struct {
    name string
    age  int
}

func main() {
    user1 := &user{
        name: "a",
        age:  30,
    }
    user2 := &user{
        name: "b",
        age:  20,
    }
    userCollection := &userCollection{
        users: []*user{user1, user2},
    }
    iterator := userCollection.createIterator()
    for iterator.hasNext() {
        user := iterator.getNext()
        fmt.Printf("User is %+v\n", user)
    }
}

輸出:

User is &{name:a age:30}
User is &{name:b age:20}

在 Go (Golang) 中透過分隔符連線字串

來源:golangbyexample.com/go-join-string-delimiter/

目錄

  • 概述

  • 程式碼:

概述

在 GO 中,字串是 UTF-8 編碼的。strings 包提供了一個 Join 方法,可以根據分隔符連線字串。

下面是該函式的簽名

func Join(a []string, sep string)

正如你所注意到的,這個函式接受一個字串切片和一個分隔符,並返回一個由分隔符連線的合併字串。分隔符或分隔符位於輸入字串切片的元素之間。請注意

  • 如果輸入切片的長度為零,它將返回一個空字串

  • 如果輸入的分隔符為空,它將輸出一個由字串切片組合而成的字串。

讓我們看看工作程式碼

程式碼:

package main

import (
    "fmt"
    "strings"
)

func main() {
    //Case 1 s contains sep. Will output slice of length 3
    res := strings.Join([]string{"ab", "cd", "ef"}, "-")
    fmt.Println(res)

    //Case 2 slice is empty. It will output a empty string
    res = strings.Join([]string{}, "-")
    fmt.Println(res)

    //Case 3 sep is empty. It will output a string combined from the slice of strings
    res = strings.Join([]string{"ab", "cd", "ef"}, "")
    fmt.Println(res)
}

輸出:

ab-cd-ef

abcdef
```*


<!--yml

類別:未分類

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

-->

# 在 Go 中解析 JSON 檔案(Golang)

> 來源:[`golangbyexample.com/json-parse-file-golang/`](https://golangbyexample.com/json-parse-file-golang/)

目錄

+   概述

+   將 JSON 檔案解析為結構體

+   將 JSON 檔案解析為對映

# **概述**

**encoding/json**包提供了一個**Unmarshal**方法,可以用於將檔案位元組轉換為結構體或對映。

**json.Unmarshal**函式可用於將 JSON 轉換為結構體或應用程式。以下是該方法的簽名:

```go
func Unmarshal(data []byte, v interface{}) error

讓我們看看以下示例:

  • 將 JSON 檔案解析為結構體

  • 將 JSON 檔案解析為對映

將 JSON 檔案解析為結構體

建立一個名為employee.json的檔案,內容如下:

{"Name":"John","Age":21}

以下是程式碼

package main

import (
	"encoding/json"
	"fmt"
	"io/ioutil"
	"log"
)

type employee struct {
	Name string `json:"Name"`
	Age  int    `json:"Age"`
}

func main() {

	var emp employee
	file, err := ioutil.ReadFile("employee.json")
	if err != nil {
		log.Fatalf("Some error occured while reading file. Error: %s", err)
	}
	err = json.Unmarshal([]byte(file), &emp)
	if err != nil {
		log.Fatalf("Error occured during unmarshaling. Error: %s", err.Error())
	}
	fmt.Printf("emp Struct: %#v\n", emp)
}

輸出

emp Struct: main.employee{Name:"John", Age:21}

在上述程式碼中,我們建立了一個員工結構體。

type employee struct {
	Name string `json:"Name"`
	Age  int    `json:"Age"`
}

員工結構體包含一些用於將 JSON 轉換為結構體的後設資料標籤。有關更多詳細資訊,請檢視此連結 – golangbyexample.com/struct-field-meta-or-tags/

這就是我們如何將檔案位元組解析到員工例項中的。

err = json.Unmarshal([]byte(file), &emp)

將 JSON 檔案解析為對映

需要注意的一點是,對映允許整數作為鍵,而 JSON 不允許整數作為鍵。JSON 僅允許字串作為鍵。因此,具有整數值作為鍵的對映在轉換為 JSON 時,鍵將變為字串值。

假設我們有以下 JSON

{"1":"John", "2": "Simon"}

以下是一個程式,將從上述內容讀取並將上述 JSON 轉換為對映:

package main

import (
	"encoding/json"
	"fmt"
	"io/ioutil"
	"log"
)

func main() {
	a := make(map[int]string)

	file, err := ioutil.ReadFile("temp.json")
	if err != nil {
		log.Fatalf("Error occured during unmarshaling. Error: %s", err.Error())
	}
	json.Unmarshal([]byte(file), &a)

	fmt.Println(a)
}

輸出

map[1:John 2:Simon]

Go 中的跳躍遊戲程式

來源:golangbyexample.com/jump-game-program-golang/

目錄

  • 概述

  • 程式

概述

提供了一個輸入陣列。陣列中的每個條目表示從該位置的最大跳躍長度。應該從第一個索引開始,如果可以到達最後一個索引,則返回 true;如果無法到達,則返回 false。

示例

Input: [2, 3, 1, 1, 4]
Output: true

Input: [3, 2, 1, 0, 4]
Output: false

在第一個示例中,有不同的方法可以到達最後一個索引。

  • 0-1-4

  • 0-2-3-4

在第二個示例中,無法到達最後一個索引。你能到達的最遠是倒數第二個索引。由於倒數第二個索引的值為零,因此無法到達最後一個索引。

還有一種變體,要求返回最少跳躍次數。我們稍後會討論這個程式。

程式

package main

import "fmt"

func canJump(nums []int) bool {
	lenNums := len(nums)
	canJumpB := make([]bool, lenNums)

	canJumpB[0] = true

	for i := 0; i < lenNums; i++ {

		if canJumpB[i] {
			valAtCurrIndex := nums[i]
			for k := 1; k <= valAtCurrIndex && i+k < lenNums; k++ {
				canJumpB[i+k] = true
			}
		}

	}

	return canJumpB[lenNums-1]
}

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

	canJumpOrNot := canJump(input)
	fmt.Println(canJumpOrNot)

	input = []int{3, 2, 1, 0, 4}

	canJumpOrNot = canJump(input)
	fmt.Println(canJumpOrNot)

}

輸出

true
false

還有一種變體,要求返回最少跳躍次數。下面是該程式

package main

import "fmt"

func jump(nums []int) int {

	lenJump := len(nums)
	minJumps := make([]int, lenJump)
	for i := 0; i < lenJump; i++ {
		minJumps[i] = -1
	}

	minJumps[0] = 0

	for i := 0; i < lenJump; i++ {
		currVal := nums[i]

		for j := 1; j <= currVal && i+j < lenJump; j++ {
			if minJumps[i+j] == -1 || minJumps[i+j] > minJumps[i]+1 {
				minJumps[i+j] = minJumps[i] + 1
			}
		}
	}

	return minJumps[lenJump-1]

}

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

	minJump := jump(input)
	fmt.Println(minJump)

	input = []int{3, 2, 1, 0, 4}

	minJump = jump(input)
	fmt.Println(minJump)

}

輸出

2
-1

注意: 檢視我們的 Golang 高階教程。該系列教程詳細且覆蓋了所有概念及示例。本教程適合希望獲得專業知識和紮實理解 Golang 的人 - Golang 高階教程

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

瞭解 Go(Golang)中的 int 或 uint 的大小和範圍。

來源:golangbyexample.com/go-size-range-int-uint/

目錄

  • 概述

  • 瞭解大小和範圍

概述

  • int 是帶符號整數資料型別。

  • uint 是無符號整數資料型別。

Go 中 intuint 的大小和範圍依賴於平臺,意味著大小和範圍取決於底層平臺是 32 位還是 64 位機器。

大小表

型別 大小 (32 位機器) 大小 (64 位機器)
int 32 位或 4 位元組 64 位或 8 位元組
uint 32 位或 4 位元組 64 位或 8 位元組

範圍表

型別 大小 (32 位機器) 大小 (64 位機器)
int -2³¹ 到 2³¹ -1 -2⁶³ 到 2⁶³ -1
uint 0 到 2³² -1 0 到 2⁶⁴ -1

瞭解大小和範圍

  • golang 的 bits 包可以幫助你瞭解系統中 intuint 的大小。bits.UintSize 是儲存此值的常量。計算方法如下:
const uintSize = 32 << (^uint(0) >> 32 & 1) // 32 or 64
  • unsafe.Sizeof() 函式也可以用於檢視 intuint 的位元組大小。

一旦知道大小,就可以根據大小推匯出範圍。請參見下面的程式碼以列印大小。

package main

import (
    "fmt"
    "math/bits"
    "unsafe"
)

func main() {
    //This is computed as 
    //const uintSize = 32 << (^uint(0) >> 32 & 1) // 32 or 64
    sizeInBits := bits.UintSize
    fmt.Printf("%d bits\n", sizeInBits)

    //Using unsafe.Sizeof() function. It will print size in bytes
    var a int
    fmt.Printf("%d bytes\n", unsafe.Sizeof(a))

    //Using unsafe.Sizeof() function. It will print size in bytes
    var b uint
    fmt.Printf("%d bytes\n", unsafe.Sizeof(b))
}

輸出:

64 bits
8 bytes
8 bytes

瞭解 Linux 上的當前使用者

來源:golangbyexample.com/know-the-current-user-on-linux/

目錄

  • 概述

概述

Linux 命令 ‘whoami’ 可用於獲取當前登入的使用者。

讓我們看看這個命令的實際效果。開啟終端並輸入命令

whoami

它將列印當前使用者。假設當前使用者是john,那麼執行上述命令將簡單地列印john

輸出

whoami
john
```*


<!--yml

分類: 未分類

日期: 2024-10-13 06:49:33

-->

# 在 Go (Golang)中查詢第 k 個不同字串的程式

> 來源:[`golangbyexample.com/kth-distinct-string-golang/`](https://golangbyexample.com/kth-distinct-string-golang/)

目錄

+   概述

+   程式

## **概述**

給定一個輸入字串陣列,可以包含重複字串。還提供一個輸入數字 **k**。其思路是找到給定輸入字串陣列中的第 k 個不同字串

讓我們透過一個例子來理解

```go
Input: ["a", "c", "b" , "c", "a", "b", "e", "d"]
k=2

Output: "d"

在上面的陣列中,下面的字串是重複的

  • “a”

  • “c”

  • “b”

上述字串未重複

  • “e”

  • “d”

由於字串 “d” 在順序中第二次出現,而 k 為 2,因此輸出為 “d”另一個例子

Input: ["xxx", "xx" "x"]
k=2

Output: "xx"

以上原因相同

程式

這裡是相同的程式。

package main

import "fmt"

func rob(nums []int) int {
	lenNums := len(nums)

	if lenNums == 0 {
		return 0
	}

	maxMoney := make([]int, lenNums)

	maxMoney[0] = nums[0]

	if lenNums > 1 {
		maxMoney[1] = nums[1]
	}

	if lenNums > 2 {
		maxMoney[2] = nums[2] + nums[0]
	}

	for i := 3; i < lenNums; i++ {
		if maxMoney[i-2] > maxMoney[i-3] {
			maxMoney[i] = nums[i] + maxMoney[i-2]
		} else {
			maxMoney[i] = nums[i] + maxMoney[i-3]
		}

	}

	max := 0
	for i := lenNums; i < lenNums; i++ {
		if maxMoney[i] > max {
			max = maxMoney[i]
		}
	}

	return max
}

func main() {
	output := rob([]int{2, 3, 4, 2})
	fmt.Println(output)

	output = rob([]int{1, 6, 8, 2, 3, 4})
	fmt.Println(output)

}

輸出

6
13

注意: 檢視我們的 Golang 高階教程。此係列的教程內容詳盡,我們盡力涵蓋所有概念及示例。這個教程適合那些希望獲得 Golang 專業知識和紮實理解的人 – Golang 高階教程

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

Go(Golang)中的直方圖最大矩形面積

來源:golangbyexample.com/largest-rectangular-area-histogram-go/

目錄

  • 概述

  • 程式

概述

有一組每個寬度為 1 單位但高度不同的柱子並排放置。柱子的高度用陣列表示

[2, 0 , 2, 1, 3, 1]

陣列表示如下

  • 柱子的總數為 5

  • 第一根柱子的高度為 2

  • 第二根柱子的高度為 0

  • 第三根柱子的高度為 2

  • 第四根柱子的高度為 1

  • 第五根柱子的高度為 3

  • 第六根柱子的高度為 1

目標是在直方圖中找到最大的矩形面積。從圖中可以看出,最大矩形面積為 4。

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

以下是解決此問題的方法。我們將使用棧,並在每個柱子的索引處找出假設該柱子完全包含在最大矩形中的面積。

  • 將給定陣列的第一個元素壓入棧中。遍歷給定陣列。對於每根柱子,我們需要找出左側最近的較小柱子和右側最近的較小柱子

  • 對於當前元素,檢查頂部元素的高度是否大於當前元素的高度

  • 如果是,那麼當前元素就是右側最近的較小柱子。棧中頂元素之後的元素是左側最近的較小柱子。

  • 彈出該元素並假設該柱子完全包含,計算最大的矩形面積。保持對最大矩形面積的跟蹤

  • 重複上述兩步,直到棧為空或頂部元素的高度小於當前元素

  • 將當前元素壓入棧中

  • 最後返回最大的矩形面積。

程式

以下是相應的程式。

package main

import "fmt"

type customStack struct {
	stack []int
}

func (c *customStack) Push(num int) {
	c.stack = append(c.stack, num)
}

func (c *customStack) Pop() (int, error) {
	length := len(c.stack)
	poppedItem := 0
	if length > 0 {
		poppedItem = c.stack[length-1]
		c.stack = c.stack[:length-1]
		return poppedItem, nil
	}
	return 0, fmt.Errorf("stack is empty")
}

func (c *customStack) Front() (int, error) {
	length := len(c.stack)
	if length > 0 {
		return c.stack[length-1], nil
	}
	return 0, fmt.Errorf("stack is empty")
}

func (c *customStack) Size() int {
	return len(c.stack)
}

func largestRectangleArea(heights []int) int {
	customStack := &customStack{}

	lenHeights := len(heights)

	customStack.Push(0)

	maxRectangleSize := heights[0]

	for i := 1; i < lenHeights; i++ {

		for customStack.Size() != 0 {
			current, _ := customStack.Front()
			if heights[current] > heights[i] {
				var rectangleUsingCurrentBar int
				current, _ := customStack.Pop()
				//Calcualte max rectangle using the current front
				previous, err := customStack.Front()
				if err != nil {
					previous = -1
				}
				rectangleUsingCurrentBar = (i - previous - 1) * heights[current]
				if rectangleUsingCurrentBar > maxRectangleSize {
					maxRectangleSize = rectangleUsingCurrentBar
				}
			} else {
				break
			}
		}
		customStack.Push(i)
	}

	front, err := customStack.Front()
	if err != nil {
		return maxRectangleSize
	}
	var rectangleUsingCurrentBar int
	for customStack.Size() != 0 {
		current, _ := customStack.Pop()
		previous, err := customStack.Front()
		if err != nil {
			previous = -1
		}
		rectangleUsingCurrentBar = (front - previous) * heights[current]
		if rectangleUsingCurrentBar > maxRectangleSize {
			maxRectangleSize = rectangleUsingCurrentBar
		}
	}
	return maxRectangleSize
}

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

輸出

4

注意: 請檢視我們的 Golang 高階教程。本系列的教程詳盡,我們儘量用示例涵蓋所有概念。本教程適合那些希望獲得專業知識並深入理解 Golang 的人 – Golang 高階教程

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

Go(Golang)中通道的長度和容量

來源:golangbyexample.com/length-and-capacity-channel-golang/

目錄

  • 概述

  • 緩衝通道的長度和容量

  • 無緩衝通道的長度和容量

  • Nil 通道的長度和容量

概述

僅緩衝通道適用長度和容量。通道的長度是通道中已有元素的數量,而緩衝通道的容量是該通道可以容納的元素數量。因此,長度實際上表示通道緩衝區中排隊的元素數量,而容量則指通道緩衝區的大小。因此,通道的長度始終小於或等於通道的容量。

  • 可以使用 len()函式獲取通道的長度

  • 可以使用 cap()函式獲取通道的容量

無緩衝通道的長度和容量始終為零

緩衝通道的長度和容量

package main

import "fmt"

func main() {
	ch := make(chan int, 3)
	ch <- 5
	fmt.Printf("Len: %d\n", len(ch))
	fmt.Printf("Capacity: %d\n", cap(ch))

	ch <- 6
	fmt.Printf("Len: %d\n", len(ch))
	fmt.Printf("Capacity: %d\n", cap(ch))

	ch <- 7
	fmt.Printf("Len: %d\n", len(ch))
	fmt.Printf("Capacity: %d\n", cap(ch))
}

輸出

Len: 1
Capacity: 3
Len: 2
Capacity: 3
Len: 3
Capacity: 3

在上面的程式碼中,首先建立了一個容量為 3 的通道。之後,我們不斷向通道傳送一些值。正如你從輸出中注意到的那樣,每次傳送操作後通道的長度增加 1,而容量始終保持為 3。

無緩衝通道的長度和容量

無緩衝通道的長度和容量始終為零

package main

import "fmt"

func main() {
    ch := make(chan int)
    fmt.Printf("Len: %d\n", len(ch))
    fmt.Printf("Capacity: %d\n", cap(ch))
}

輸出

Len: 0
Capacity: 0

Nil 通道的長度和容量

Nil 通道的長度和容量始終為零

package main

import "fmt"

func main() {
	var ch chan int

	fmt.Printf("Len: %d\n", len(ch))
	fmt.Printf("Capacity: %d\n", cap(ch))
}

輸出

Len: 0
Capacity: 0

以下是不同型別通道上len()cap()的結果摘要表

命令 無緩衝通道(未關閉且不為 nil) 緩衝通道(未關閉且不為 nil) 已關閉通道 Nil 通道
長度 0 通道緩衝區中排隊的元素數量 -如果是無緩衝通道則為 0-如果是緩衝通道則為緩衝區中排隊的元素數量 0
容量 0 通道緩衝區的大小 -如果是無緩衝通道則為 0-如果是緩衝通道則為緩衝區的大小 0

Go(Golang)中對映的長度

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

Golang 內建函式 len() 可用於獲取對映的長度,即對映中鍵值對的數量。以下是使用此函式在對映上操作的格式。

len(mapName)

讓我們看一個程式

package main

import "fmt"

func main() {
    //Declare
    employeeSalary := make(map[string]int)

    //Adding a key value
    employeeSalary["Tom"] = 2000
    employeeSalary["Sam"] = 1200

    lenOfMap := len(employeeSalary)
    fmt.Println(lenOfMap)
}

輸出

2

Go 語言中的字串長度

來源:golangbyexample.com/length-of-string-golang/

在 Golang 中,字串是位元組序列。字串字面量實際上表示的是 UTF-8 位元組序列。在 UTF-8 中,ASCII 字元是單位元組,對應於前 128 個 Unicode 字元。所有其他字元佔用 1 到 4 個位元組。為了更好地理解,考慮以下字串

sample := "a£c"

在上述字串中

  • ‘a’根據 UTF-8 佔用一個位元組

  • ‘£’根據 UTF-8 佔用兩個位元組

  • ‘b’根據 UTF-8 佔用一個位元組

上述字串總共有 1+2+1 = 4 個位元組。因此,當我們嘗試使用標準的len()函式列印字串的長度時,它會輸出 4,而不是 3,因為len()函式返回的是字串中的位元組數。

fmt.Printf("Length is %d\n", len(sample))

因此,獨立的 for 迴圈不能用於遍歷字串的所有字元,因為它將遍歷位元組而不是字元。因此,下面的for迴圈將迭代四次,並列印對應於該索引的位元組值。

for i := 0; i < len(sample); i++ {
    fmt.Printf("%c\n", sample[i])
 }

它將輸出下面的字串,這與示例字串不同

a£b

現在我們提到了使用 len()函式和 for 迴圈的上述限制,讓我們看看兩種計算字串長度的方法。

  • 使用utf8 包的 RuneCountInString方法

  • 使用 for-range 迴圈

  • 透過將字串轉換為 rune 陣列。

使用 utf8 包的RuneCountInString方法

golang 的 utf8 包提供了一個 RuneCountInString 方法,可以用來獲取字串的長度。它正確地計算字串中的 rune 數量。

golang.org/pkg/unicode/utf8/#RuneCountInString

package main

import (
	"fmt"
	"unicode/utf8"
)

func main() {
	sample := "a£b"

	fmt.Printf("Length of given string is %d\n", utf8.RuneCountInString(sample))
}

輸出

Length of given string is 3

使用 for-range 迴圈

for-range 遍歷字串中的 Unicode 點(在 golang 中也稱為 rune),並將正確輸出 a, £, b。因此,它也可以用於計算字串的長度。以下是使用 for-range 與字串時的格式

for index, character := range string {
    //Do something with index and character
}

示例程式碼

package main

import "fmt"

func main() {
	sample := "a£b"

	len := 0
	//With index and value
	fmt.Println("Both Index and Value")
	for i, letter := range sample {
		len++
		fmt.Printf("Start Index: %d Value:%s\n", i, string(letter))
	}

	fmt.Printf("Length of given string is %d\n", len)
}

輸出

Start Index: 0 Value:a
Start Index: 1 Value:£
Start Index: 3 Value:b
Length of given string is 3

透過將字串轉換為 rune 陣列

一個 rune 表示一個 Unicode 點。透過將字串轉換為 rune 陣列,基本上就是建立該字串的 Unicode 點陣列。因此,一旦字串被轉換為 rune 陣列,它就可以用來遍歷字串的所有字元。

package main

import "fmt"

func main() {
	sample := "a£b"

	runeSample := []rune(sample)

	fmt.Printf("Length of given string is %d\n", len(runeSample))
}

輸出

Length of given string is 3

電話號碼字母組合程式在 Go (Golang)中

來源:golangbyexample.com/letter-combinations-phone-golang/

目錄

  • 概述

  • 程式

概述

給定一個輸入字串,其中包含一些數字。數字與字母的對映類似於電話鍵盤。

2 = either "a", "b" or "c"
3 = either "d", "e" or "f"
4 = either "g", "h" or "i"
5 = either "j", "k" or "l"
6 = either "m", "n" or "co"
7 = either "p", "q" "r" or "s"
8 = either "t", "u" or "v"
9 = either "w", "x", "y" or "z"

因此,給定的輸入字串僅包含數字。目標是返回所有字母組合。

示例

Input: "3"
Output: [d e f]

Input: "34"
Output: [dg dh di eg eh ei fg fh fi]

Input: "345"
Output: [dgj dgk dgl dhj dhk dhl dij dik dil egj egk egl ehj ehk ehl eij eik eil fgj fgk fgl fhj fhk fhl fij fik fil]

程式

這裡是相同程式的程式碼。

package main

import "fmt"

func letterCombinations(digits string) []string {
	if digits == "" {
		return nil
	}
	letterMap := make(map[string][]string)

	letterMap["2"] = []string{"a", "b", "c"}
	letterMap["3"] = []string{"d", "e", "f"}
	letterMap["4"] = []string{"g", "h", "i"}
	letterMap["5"] = []string{"j", "k", "l"}
	letterMap["6"] = []string{"m", "n", "o"}
	letterMap["7"] = []string{"p", "q", "r", "s"}
	letterMap["8"] = []string{"t", "u", "v"}
	letterMap["9"] = []string{"w", "x", "y", "z"}

	runeDigits := []rune(digits)
	length := len(runeDigits)

	temp := ""

	return letterCombinationsUtil(runeDigits, 0, length, temp, letterMap)

}

func letterCombinationsUtil(runeDigits []rune, start, length int, temp string, letterMap map[string][]string) []string {

	if start == length {
		return []string{temp}
	}

	currentDigit := string(runeDigits[start])

	letters := letterMap[currentDigit]

	final := make([]string, 0)
	for _, val := range letters {
		t := temp + val
		output := letterCombinationsUtil(runeDigits, start+1, length, t, letterMap)
		final = append(final, output...)
	}
	return final
}

func main() {

	output := letterCombinations("3")
	fmt.Println(output)

	output = letterCombinations("34")
	fmt.Println(output)

	output = letterCombinations("345")
	fmt.Println(output)
}

輸出

[d e f]
[dg dh di eg eh ei fg fh fi]
[dgj dgk dgl dhj dhk dhl dij dik dil egj egk egl ehj ehk ehl eij eik eil fgj fgk fgl fhj fhk fhl fij fik fil]

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

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

Golang 中二叉樹的層序遍歷

來源:golangbyexample.com/level-order-traversal-binary-tree-golang/

目錄

  • 概述

  • 程式

概述

目標是逐層列印二叉樹。例如,假設我們有如下二叉樹

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

這裡我們有

  • 第 1 級的節點 1

  • 第 2 級的節點 2 和節點 3

  • 第 3 級的節點 4、節點 5 和節點 6

所以輸出應該是

[[1] [2 3] [4 5 6]]

程式

下面是相同的程式

package main

import (
	"fmt"
)

type TreeNode struct {
	Val   int
	Left  *TreeNode
	Right *TreeNode
}

func levelOrder(root *TreeNode) [][]int {
	levelMapNode := make(map[int][]int)
	visit(root, 0, &levelMapNode)

	output := make([][]int, 0)

	i := 0
	for true {
		_, ok := levelMapNode[i]

		if ok {
			output = append(output, levelMapNode[i])
		} else {
			break
		}
		i = i + 1

	}
	return output

}

func visit(root *TreeNode, level int, levelMapNode *map[int][]int) {
	if root == nil {
		return
	}
	_, ok := (*levelMapNode)[level]
	if ok {
		(*levelMapNode)[level] = append((*levelMapNode)[level], root.Val)
	} else {
		(*levelMapNode)[level] = []int{root.Val}
	}

	if root.Left != nil {
		visit(root.Left, level+1, levelMapNode)
	}

	if root.Right != nil {
		visit(root.Right, level+1, levelMapNode)
	}
	return
}

func main() {
	root := TreeNode{Val: 1}
	root.Left = &TreeNode{Val: 2}
	root.Right = &TreeNode{Val: 3}
	root.Right.Left = &TreeNode{Val: 4}
	root.Right.Right = &TreeNode{Val: 5}

	output := levelOrder(&root)
	fmt.Println(output)

}

輸出

[[1] [2 3] [4 5 6]]

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

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

Golang 中的連結串列

來源:golangbyexample.com/singly-linked-list-in-golang/

單連結串列是一種簡單的連結串列,只允許向一個方向遍歷,即向前。連結串列中的每個節點包含資料部分和指向下一個節點的指標。

以下實現的連結串列支援以下操作:

  1. 新增前部

  2. 新增後部

  3. 移除前部

  4. 移除後部

  5. 遍歷

  6. 前部

  7. 大小

package main

import "fmt"

type ele struct {
    name string
    next *ele
}

type singleList struct {
    len  int
    head *ele
}

func initList() *singleList {
    return &singleList{}
}

func (s *singleList) AddFront(name string) {
    ele := &ele{
        name: name,
    }
    if s.head == nil {
        s.head = ele
    } else {
        ele.next = s.head
        s.head = ele
    }
    s.len++
    return
}

func (s *singleList) AddBack(name string) {
    ele := &ele{
        name: name,
    }
    if s.head == nil {
        s.head = ele
    } else {
        current := s.head
        for current.next != nil {
            current = current.next
        }
        current.next = ele
    }
    s.len++
    return
}

func (s *singleList) RemoveFront() error {
    if s.head == nil {
        return fmt.Errorf("List is empty")
    }
    s.head = s.head.next
    s.len--
    return nil
}

func (s *singleList) RemoveBack() error {
    if s.head == nil {
        return fmt.Errorf("removeBack: List is empty")
    }
    var prev *ele
    current := s.head
    for current.next != nil {
        prev = current
        current = current.next
    }
    if prev != nil {
        prev.next = nil
    } else {
        s.head = nil
    }
    s.len--
    return nil
}

func (s *singleList) Front() (string, error) {
    if s.head == nil {
        return "", fmt.Errorf("Single List is empty")
    }
    return s.head.name, nil
}

func (s *singleList) Size() int {
    return s.len
}

func (s *singleList) Traverse() error {
    if s.head == nil {
        return fmt.Errorf("TranverseError: List is empty")
    }
    current := s.head
    for current != nil {
        fmt.Println(current.name)
        current = current.next
    }
    return nil
}

func main() {
     singleList := initList()
    fmt.Printf("AddFront: A\n")
    singleList.AddFront("A")
    fmt.Printf("AddFront: B\n")
    singleList.AddFront("B")
    fmt.Printf("AddBack: C\n")
    singleList.AddBack("C")

    fmt.Printf("Size: %d\n", singleList.Size())

    err := singleList.Traverse()
    if err != nil {
        fmt.Println(err.Error())
    }

    fmt.Printf("RemoveFront\n")
    err = singleList.RemoveFront()
    if err != nil {
        fmt.Printf("RemoveFront Error: %s\n", err.Error())
    }

    fmt.Printf("RemoveBack\n")
    err = singleList.RemoveBack()
    if err != nil {
        fmt.Printf("RemoveBack Error: %s\n", err.Error())
    }

    fmt.Printf("RemoveBack\n")
    err = singleList.RemoveBack()
    if err != nil {
        fmt.Printf("RemoveBack Error: %s\n", err.Error())
    }

    fmt.Printf("RemoveBack\n")
    err = singleList.RemoveBack()
    if err != nil {
        fmt.Printf("RemoveBack Error: %s\n", err.Error())
    }

    err = singleList.Traverse()
    if err != nil {
        fmt.Println(err.Error())
    }

   fmt.Printf("Size: %d\n", singleList.Size())
}

輸出:

AddFront: A
AddFront: B
AddBack: C
Size: 3
B
A
C
RemoveFront
RemoveBack
RemoveBack
RemoveBack
RemoveBack Error: removeBack: List is empty
TranverseError: List is empty
Size: 0
  • 資料* go* 連結* 單連結串列* 單一* 結構

列出 Go 中的所有環境變數

來源:golangbyexample.com/list-all-env-variables-go/

目錄

  • 概述

  • 程式碼:

概述

os 包提供了一個 Environ() 函式,用於獲取所有環境變數的列表。

  • 獲取所有環境變數。它返回一個字串陣列。
func Environ() []string 

還有一種方法可以清除所有環境變數。Clearenv()函式可以用來實現同樣的功能。

func Clearenv()

程式碼:

package main

import (
    "fmt"
    "log"
    "os"
)

func main() {
    //Set env a to b
    err := os.Setenv("a", "b")
    if err != nil {
        log.Fatal(err)
    }

    err = os.Setenv("c", "d")
    if err != nil {
        log.Fatal(err)
    }

    //Get all env variables
    fmt.Println(os.Environ())

    //Clear all env variables
    os.Clearenv()

    //Again get all env variable
    fmt.Println(os.Environ())
}

輸出:

List of all env varialbes on your system including a and b
```*


<!--yml

分類:未分類

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

-->

# 在 Go(Golang)中載入 .env 或環境檔案。

> 來源:[`golangbyexample.com/load-env-fiie-golang/`](https://golangbyexample.com/load-env-fiie-golang/)

目錄

+   概述

+   程式 

# **概述**

**gotenv** 包在 Golang 中可用於載入 **.env** 或 **環境** 檔案。

[`github.com/joho/godotenv`](https://github.com/joho/godotenv)

以下是函式的簽名。

```go
func Load(filenames ...string) (err error) 

它接受可變數量的引數,每個引數可以是需要載入的 .env 檔名。

程式

建立一個 local.env 檔案,幷包含以下內容。

STACK=DEV
DATABASE=SQL

這是程式。

package main

import (
	"fmt"
	"log"
	"os"

	"github.com/joho/godotenv"
)

func main() {
	err := godotenv.Load("local.env")
	if err != nil {
		log.Fatalf("Some error occured. Err: %s", err)
	}

	val := os.Getenv("STACK")
	fmt.Println(val)

	val = os.Getenv("DATABASE")
	fmt.Println(val)
}

輸出

DEV
SQL

它載入 local.env 檔案並給出正確的輸出。

它還可以用於載入多個 .env 檔案。建立一個新的檔案 test.env,幷包含以下內容。

TEST=UNIT
package main

import (
	"fmt"
	"log"
	"os"

	"github.com/joho/godotenv"
)

func main() {
	err := godotenv.Load("local.env", "test.env")
	if err != nil {
		log.Fatalf("Some error occured. Err: %s", err)
	}

	val := os.Getenv("STACK")
	fmt.Println(val)

	val = os.Getenv("DATABASE")
	fmt.Println(val)

	val = os.Getenv("TEST")
	fmt.Println(val)
}

輸出

DEV
SQL
UNIT

如果你沒有向 Load 函式提供任何引數,則預設情況下它將載入當前目錄中的 .env 檔案。

在當前目錄中建立一個名為 .env 的檔案,幷包含以下內容。

STACK=DEV
DATABASE=SQL
package main

import (
	"fmt"
	"log"
	"os"

	"github.com/joho/godotenv"
)

func main() {
	err := godotenv.Load()
	if err != nil {
		log.Fatalf("Some error occured. Err: %s", err)
	}

	val := os.Getenv("STACK")
	fmt.Println(val)

	val = os.Getenv("DATABASE")
	fmt.Println(val)
}

請注意,在上述程式中,我們沒有向 Load 函式傳遞任何引數。

輸出

DEV
SQL

這部分是關於在 Golang 中載入 .env 檔案的。

注意: 請檢視我們的 Golang 高階教程。本系列教程詳盡,我們嘗試涵蓋所有概念和示例。本教程適合希望深入理解 Golang 的人——Golang 高階教程

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

Go 語言中的數字對數

來源:golangbyexample.com/log-of-number-go-golang/

目錄

概述

  • 自然對數

  • 程式碼

  • 二進位制指數對數(log e)

    • 程式碼
  • 二進位制對數(log 2)

    • 程式碼
  • 十進位制對數(log 10)

    • 程式碼

概述

在本教程中,我們將看到三種可能的對數型別

  • 自然對數

  • 二進位制指數對數(log e)

  • 二進位制對數(log 2)

  • 十進位制對數(log 10)

自然對數

GO 的math包提供了一個Log方法,可用於獲取一個數字的自然對數

以下是函式的簽名。它的輸入為float64數字,並返回一個float64

func Log(x float64) float64

另外,Logb函式的一些特殊情況是

  • Log(±Inf) = +Inf

  • Log(0) = -Inf

  • Log(NaN) = NaN

  • Log(x < 0) = NaN

程式碼

package main

import (
    "fmt"
    "math"
)

func main() {
    res := math.Log(4)
    fmt.Println(res)

    res = math.Log(10.2)
    fmt.Println(res)

    res = math.Log(-10)
    fmt.Println(res)
}

輸出:

1.3862943611198906
2.322387720290225
NaN

二進位制指數對數(log e)

golang 的math包提供了一個Logb方法,可用於獲取一個數字的二進位制指數

以下是函式的簽名。它的輸入為float64數字,並返回一個float64

func Logb(x float64) float64

另外,Logb函式的一些特殊情況是

  • Logb(±Inf) = +Inf

  • Logb(0) = -Inf

  • Logb(NaN) = NaN

程式碼

package main

import (
    "fmt"
    "math"
)

func main() {
    res := math.Logb(4)
    fmt.Println(res)

    res = math.Logb(10.2)
    fmt.Println(res)

    res = math.Logb(-10)
    fmt.Println(res)
}

輸出:

2
3
3

二進位制對數(log 2)

golang 的math包提供了一個Log2方法,可用於獲取一個數字的二進位制對數或以 2 為底的對數

以下是函式的簽名。它的輸入為 float64 數字,並返回一個 float64。

另外,Log2函式的一些特殊情況是

  • Log2(±Inf) = +Inf

  • Log2(0) = -Inf

  • Log2(NaN) = NaN

  • Log2(x < 0) = NaN

程式碼

package main

import (
    "fmt"
    "math"
)

func main() {
    res := math.Log2(4)
    fmt.Println(res)

    res = math.Log2(10.2)
    fmt.Println(res)

    res = math.Log2(-10)
    fmt.Println(res)
}

輸出:

2
3.321928094887362
NaN

十進位制對數(log 10)

Go 的math包提供了一個Log10方法,可用於獲取一個數字的十進位制對數或以 10 為底的對數

以下是函式的簽名。它的輸入為 float64 數字,並返回一個 float64。

func Log10(x float64) float64

另外,Log10函式的一些特殊情況是

  • Log10(±Inf) = +Inf

  • Log10(0) = -Inf

  • Log10(NaN) = NaN

  • Log10(x < 0) = NaN

程式碼

package main

import (
    "fmt"
    "math"
)

func main() {
    res := math.Log10(100)
    fmt.Println(res)

    res = math.Log10(10)
    fmt.Println(res)

    res = math.Log10(-10)
    fmt.Println(res)
}

輸出:

2
1
NaN

Go(Golang)中的字串集合的最長公共字首

來源:golangbyexample.com/longest-common-prefix-golang/

目錄

  • 概述

  • 程式

概述

給定一個字串陣列,目標是找到該陣列中最長的公共字首。如果沒有公共字首,應該輸出空字串。

示例 1

Input: ["fan", "fat", "fame"]
Output: "fa"

示例 2

Input: ["bat", "van", "cat"]
Output: ""

程式

以下是相同的程式

package main

import "fmt"

func longestCommonPrefix(strs []string) string {
	lenStrs := len(strs)

	if lenStrs == 0 {
		return ""
	}

	firstString := strs[0]

	lenFirstString := len(firstString)

	commonPrefix := ""
	for i := 0; i < lenFirstString; i++ {
		firstStringChar := string(firstString[i])
		match := true
		for j := 1; j < lenStrs; j++ {
			if (len(strs[j]) - 1) < i {
				match = false
				break
			}

			if string(strs[j][i]) != firstStringChar {
				match = false
				break
			}

		}

		if match {
			commonPrefix += firstStringChar
		} else {
			break
		}
	}

	return commonPrefix
}

func main() {
	output := longestCommonPrefix([]string{"fan", "fat", "fame"})
	fmt.Println(output)

	output = longestCommonPrefix([]string{"bat", "van", "cat"})
	fmt.Println(output)
}

輸出:

"fa"
""

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

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

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

Go (Golang) 中的最長連續序列程式

來源:golangbyexample.com/longest-consecutive-sequence-golang/

目錄

  • 概述

  • 程式

概述

給定一個整數陣列。找到其中最長連續序列的長度。讓我們看看一個示例來理解它。

示例 1

Input: [4,7,3,8,2,1]
Output: 4
Reason: The longest consecutive sequence is [1,2,3,4]

示例 2

Input: [4,7,3,8,2,1,9,24,10,11]
Output: 5
Reason: The longest consecutive sequence is [7,8,9,10,11]

天真的想法是對陣列進行排序並返回最長的連續序列。但我們可以在 O(n) 時間內完成這個任務。想法是使用雜湊表。下面是這個思路。

  • 將每個數字儲存在雜湊表中。

  • 然後從每個數字開始,找到以該數字開頭的最長連續序列的長度。如果一個數字是 n,我們嘗試在雜湊中找到 n+1, n+2… 並獲取從該數字開始的最長連續序列的長度。

  • 如果步驟 2 中找到的長度大於之前找到的最長連續序列長度,則更新最長連續序列長度。

程式

下面是相應的程式。

package main

import "fmt"

func longestConsecutive(nums []int) int {
	numsMap := make(map[int]int)

	lenNums := len(nums)

	for i := 0; i < lenNums; i++ {
		numsMap[nums[i]] = 0
	}

	maxLCS := 0
	for i := 0; i < lenNums; i++ {
		currentLen := 1
		counter := 1

		for {
			val, ok := numsMap[nums[i]+counter]
			if ok {
				if val != 0 {
					currentLen += val
					break
				} else {
					currentLen += 1
					counter += 1
				}
			} else {
				break
			}
		}

		if currentLen > maxLCS {
			maxLCS = currentLen
		}
		numsMap[nums[i]] = currentLen
	}

	return maxLCS
}

func main() {
	output := longestConsecutive([]int{4, 7, 3, 8, 2, 1})
	fmt.Println(output)

	output = longestConsecutive([]int{4, 7, 3, 8, 2, 1, 9, 24, 10, 11})
	fmt.Println(output)

}

輸出:

4
5

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

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

另外,可以在這裡檢視我們的系統設計教程系列 – 系統設計教程系列

相關文章