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

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

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

另外,可以在这里查看我们的系统设计教程系列 – 系统设计教程系列