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

通过示例学习 Go 语言 2023(三十二)

Go(Golang)中的映射切片

来源:golangbyexample.com/slice-map-golang/

目录

  • 概述

  • 程序

概述

在 Golang 中也可以创建映射数据类型的切片。事实上,Go 中可以创建任何数据类型的切片。下面是创建映射切片的一个简单示例

程序

package main

import "fmt"

func main() {
	maps := make([]map[string]string, 3)

	map1 := make(map[string]string)
	map1["1"] = "a"

	map2 := make(map[string]string)
	map2["2"] = "b"

	map3 := make(map[string]string)
	map3["3"] = "c"

	maps[0] = map1
	maps[1] = map2
	maps[2] = map3

	for _, m := range maps {
		fmt.Println(m)
	}
}

输出

map[1:a]
map[2:b]
map[3:c]

在上述程序中,我们创建了三种类型为map[string]string的映射

map1 := make(map[string]string)
map1["1"] = "a"

map2 := make(map[string]string)
map2["2"] = "b"

map3 := make(map[string]string)
map3["3"] = "c"

我们也像这样创建了一个映射数据类型的切片

maps := make([]map[string]string, 3)

这就是我们如何创建一个映射切片

查看我们的 Golang 高级教程。本系列教程内容详尽,我们试图通过示例覆盖所有概念。这个教程是为那些希望获得专业知识和对 Golang 有深入理解的人准备的 – Golang 高级教程

如果你有兴趣了解所有设计模式如何在 Golang 中实现。如果是的话,这篇文章适合你 –所有设计模式 Golang

Go (Golang) 中的结构体切片

来源:golangbyexample.com/slice-struct-golang/

目录

  • 概述

  • 程序

概述

在 Golang 中创建结构体切片是可能的。实际上,可以为 Go 中的任何数据类型创建切片。下面是创建结构体切片的简单示例

程序

package main

import "fmt"

type employee struct {
	name string
	age  int
}

func main() {
	employees := make([]employee, 3)

	employees[0] = employee{name: "John", age: 21}
	employees[1] = employee{name: "Simon", age: 25}
	employees[2] = employee{name: "David", age: 18}

	for _, e := range employees {
		fmt.Println(e)
	}
}

输出

{John 21}
{Simon 25}
{David 18}

在上述程序中,我们创建了一个名为 employee 的结构体

type employee struct {
	name string
	age  int
}

然后我们创建了一个结构体的切片,如下所示

employees := make([]employee, 3)

这就是我们如何创建结构体切片

注意: 请查看我们的 Golang 高级教程。本系列教程内容详尽,我们尽力涵盖所有概念及示例。此教程适合希望获得专业知识和深入理解 Golang 的人——Golang 高级教程

如果你有兴趣了解如何在 Golang 中实现所有设计模式。如果是的话,这篇文章适合你——所有设计模式 Golang

Go(Golang)中的布尔切片或数组

来源:golangbyexample.com/slice-array-bool-golang/

目录

  • 概述

  • 布尔切片

  • 布尔数组

概述

在 Golang 中,可以创建bool数据类型的切片或数组。实际上,可以创建任何数据类型的切片或数组。本教程包含创建布尔数据类型切片或数组的简单示例。

这里需要补充的是,在 golang 中,数组是固定大小的,切片可以有可变大小。更多细节见这里

数组 – golangbyexample.com/understanding-array-golang-complete-guide/

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

布尔切片

package main

import "fmt"

func main() {

	//First Way
	var booleans_first []bool
	booleans_first = append(booleans_first, true)
	booleans_first = append(booleans_first, false)
	booleans_first = append(booleans_first, true)

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

	//Second Way
	booleans_second := make([]bool, 3)
	booleans_second[0] = false
	booleans_second[1] = true
	booleans_second[2] = false

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

输出

Output for First slice of booleans
true
false
true

Output for Second slice of booleans
false
true
false

我们有两种创建布尔切片的方法。第一种方法是

var booleans_first []bool
booleans_first = append(booleans_first, true)
booleans_first = append(booleans_first, false)
booleans_first = append(booleans_first, true)

第二种方法,我们使用 make 命令创建布尔切片

booleans_second := make([]bool, 3)
booleans_second[0] = false
booleans_second[1] = true
booleans_second[2] = false

两种方法都可行。这是我们如何创建布尔切片

布尔数组

package main

import "fmt"

func main() {

	var booleans_first [3]bool

	booleans_first[0] = true
	booleans_first[1] = false
	booleans_first[2] = true

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

	booleans_second := [3]bool{
		false,
		true,
		false,
	}

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

输出

Output for First Array of booleans
true
false
true

Output for Second Array of booleans
false
true
false

我们有两种创建数组的方法。第一种方法是

var booleans_first [3]bool
booleans_first[0] = true
booleans_first[1] = false
booleans_first[2] = true

在第二种方法中,我们直接用创建的布尔值初始化数组

booleans_second := [3]bool{
	false,
	true,
	false,
}

查看我们的 Golang 高级教程。本系列教程内容详尽,我们尽力覆盖所有概念和示例。本教程适合那些希望获得专业知识并深入理解 golang 的读者 – Golang 高级教程

如果你有兴趣了解所有设计模式如何在 Golang 中实现。如果是的话,这篇文章适合你 –所有设计模式 Golang

Go(Golang)中的通道切片或数组

来源:golangbyexample.com/slice-array-channel-golang/

目录

概述

  • 通道切片

  • 通道数组

概述

在 Golang 中也可以创建通道数据类型的切片或数组。事实上,可以创建任何数据类型的切片或数组。本教程包含了创建 Golang 中通道切片或数组的简单示例。

在此补充,Golang 中的数组是固定大小的,而切片可以是可变大小的。

更多细节见此处

数组 – golangbyexample.com/understanding-array-golang-complete-guide/

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

通道切片

package main

import "fmt"

func main() {

	channel1 := make(chan int)
	channel2 := make(chan int)
	channel3 := make(chan int)

	//First Way
	var channels_first []chan int
	channels_first = append(channels_first, channel1)
	channels_first = append(channels_first, channel2)
	channels_first = append(channels_first, channel3)

	fmt.Println("\nOutput for First slice of channels")
	for _, c := range channels_first {
		fmt.Println(c)
	}

	//Second Way
	channels_second := make([]chan int, 3)
	channels_second[0] = channel1
	channels_second[1] = channel2
	channels_second[2] = channel3

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

输出

Output for First slice of channels
0xc000118000
0xc000118060
0xc0001180c0

Output for Second slice of channels
0xc000118000
0xc000118060
0xc0001180c0

输出在你的机器上会有所不同,因为这是一个地址。

在上面的程序中,我们创建了三个数据类型为 int 的通道。

channel1 := make(chan int)
channel2 := make(chan int)
channel3 := make(chan int)

我们有两种创建通道切片的方法。第一种方式是

var channels_first []chan int
channels_first = append(channels_first, channel1)
channels_first = append(channels_first, channel2)
channels_first = append(channels_first, channel3)

在第二种方法中,我们使用make命令来创建通道切片。

channels_second := make([]chan int, 3)
channels_second[0] = channel1
channels_second[1] = channel2
channels_second[2] = channel3

无论哪种方式都可以。这就是我们如何创建通道切片的方法。

通道数组

package main

import "fmt"

func main() {
	channel1 := make(chan int)
	channel2 := make(chan int)
	channel3 := make(chan int)

	var channels_first [3]chan int

	channels_first[0] = channel1
	channels_first[1] = channel2
	channels_first[2] = channel3

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

	channel_second := [3]chan int{
		channel1,
		channel2,
		channel3,
	}

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

输出

Output for First Array of channels
0xc00008c060
0xc00008c0c0
0xc00008c120

Output for Second Array of channels
0xc00008c060
0xc00008c0c0
0xc00008c120

输出在你的机器上会有所不同,因为这是一个地址。

在上面的程序中,我们创建了三个数据类型为 int 的通道。

channel1 := make(chan int)
channel2 := make(chan int)
channel3 := make(chan int)

我们有两种创建数组的方法。第一种方式是

var channels_first [3]chan int
channels_first[0] = channel1
channels_first[1] = channel2
channels_first[2] = channel3

在第二种方法中,我们直接用创建的通道初始化数组。

channel_second := [3]chan int{
	channel1,
	channel2,
	channel3,
}

查看我们的 Golang 高级教程。本系列教程详细而全面,我们努力覆盖所有概念并附有示例。本教程适合那些希望获得专业知识和深入理解 Golang 的人——Golang 高级教程

如果你对如何在 Golang 中实现所有设计模式感兴趣,如果是的话,那么这篇文章适合你——所有设计模式 Golang

在 Go 中排序自定义结构(Golang)

来源:golangbyexample.com/sort-custom-struct-collection-golang/

目录

** 介绍

  • 完整工作代码:

介绍

GO 有一个 sort 包,提供了用于排序切片和用户定义类型的实用工具原语。任何集合只要实现了 sort.Interface,就可以通过 GO 的 sort 包的 Sort 函数进行排序。

以下是 sort.Interface 的方法。

golang.org/pkg/sort/#Interface

type Interface interface {
    // Len is the number of elements in the collection.
    Len() int

    // Less reports whether the element with
    // index i should sort before the element with index j.
    Less(i, j int) bool

    // Swap swaps the elements with indexes i and j.
    Swap(i, j int)
}

让我们看一个工作示例,说明如何使用 sort.Interface 对用户定义的结构体进行排序。在下面的示例中。

  • 我们创建了一个名为 employee 的自定义结构,字段包括 name 和以美元为单位的 salary

  • 我们有一个 employeeList,它保存 employee 的列表。

  • employeeList 实现了 Len()、Less()、Swap() 方法,因此它实现了 sort.Interface

  • 我们按薪资从高到低对员工进行排序。要排序 employeeList,我们将其传递给 sort.Sort() 函数。

完整工作代码:

package main

import (
    "fmt"
    "sort"
)

type employee struct {
    name   string
    salary int
}

type employeeList []employee

func (e employeeList) Len() int {
    return len(e)
}

func (e employeeList) Less(i, j int) bool {
    return e[i].salary > e[j].salary
}

func (e employeeList) Swap(i, j int) {
    e[i], e[j] = e[j], e[i]
}

func main() {
    eList := []employee{
        employee{name: "John", salary: 3000},
        employee{name: "Bill", salary: 4000},
        employee{name: "Sam", salary: 1000},
    }
    sort.Sort(employeeList(eList))
    for _, employee := range eList {
        fmt.Printf("Name: %s Salary %d\n", employee.name, employee.salary)
    }
}

输出:

Name: Bill Salary 4000
Name: John Salary 3000
Name: Sam Salary 1000

要从最低薪资排序到最高薪资,我们需要用 ‘>’ 符号更改 Less 函数。

func (e employeeList) Less(i, j int) bool {
    return e[i].salary > e[j].salary
}

修改后,当我们运行程序时,输出将是:

Name: Sam Salary 1000
Name: John Salary 3000
Name: Bill Salary 4000

在 Go (Golang)中排序部分切片

来源:golangbyexample.com/sort-part-slice-go/

概述

Golang 的sort.Slice包可用于排序完整切片或部分切片,完整切片按升序排序

package main

import (
	"fmt"
	"sort"
)

func main() {

	nums := []int{3, 4, 2, 1}
	sort.Slice(nums, func(i, j int) bool {
		return nums[i] < nums[j]
	})
	fmt.Println(nums)
}

输出

[1,2,3,4]

完整切片按降序排序

package main
import (
    "fmt"
    "sort"
)
func main() {
    nums := []int{3, 4, 2, 1}
    sort.Slice(nums, func(i, j int) bool {
        return nums[i] > nums[j]
    })
    fmt.Println(nums)
}

输出

[4 3 2 1]

部分切片排序

package main

import (
	"fmt"
	"sort"
)

func main() {

	nums := []int{3, 4, 2, 1}
	start := 2
	end := 4
	sort.Slice(nums[start:end], func(i, j int) bool {
		return nums[start+i] < nums[start+j]
	})
	fmt.Println(nums)
}

输出

[3 4 1 2]

请注意,它已将最后两个元素按升序排列。

注意: 请查看我们的 Golang 高级教程。本系列教程内容详尽,力求用实例覆盖所有概念。该教程适合希望获得专业知识和对 Golang 有扎实理解的学习者 - Golang 高级教程

如果你有兴趣了解如何在 Golang 中实现所有设计模式。那么这篇文章就是为你准备的 - 所有设计模式 Golang

在 Go (Golang)中以升序和降序排序整型切片

来源:golangbyexample.com/sort-slice-asc-desc-golang/

目录

** 以升序排序切片

  • 以降序排序切片

以升序排序切片

sort.Ints包可以用来排序整个切片或切片的一部分。它将字符串排序为升序。

下面是该方法的签名。

pkg.go.dev/sort#Ints

func Ints(x []int)

它将切片‘x’作为参数,并对切片‘x’进行就地排序。

下面是相同程序的代码。

package main

import (
	"fmt"
	"sort"
)

func main() {

	nums := []int{3, 4, 2, 1}
	fmt.Printf("Before: %v", nums)
	sort.Ints(nums)
	fmt.Printf("\nAfter: %v", nums)
}

输出

Before: [3 4 2 1]
After: [1 2 3 4]

以降序排序切片

为了以降序对切片进行排序,我们将使用sort包的Slice方法。

pkg.go.dev/sort#Slice

下面是该方法的签名。

func Slice(x any, less func(i, j int) bool)

这个函数接受两个参数

  • x any – 这里的 any 只是一个空接口 pkg.go.dev/builtin#any

  • less func(i, j int) – 这个函数实际上就是一个比较函数。

我们可以使用这个比较函数来决定切片中元素的降序。下面是一个例子。

package main

import (
	"fmt"
	"sort"
)

func main() {

	nums := []int{3, 4, 2, 1}
	fmt.Printf("Before: %v", nums)
	sort.Slice(nums, func(i, j int) bool {
		return nums[i] > nums[j]
	})
	fmt.Printf("\nAfter: %v", nums)
}

输出

Before: [3 4 2 1]
After: [4 3 2 1]

实际上,你也可以使用sort.Slice方法以降序排序切片。下面是一个例子。

package main

import (
	"fmt"
	"sort"
)

func main() {

	nums := []int{3, 4, 2, 1}
	fmt.Printf("Before: %v", nums)
	sort.Slice(nums, func(i, j int) bool {
		return nums[i] < nums[j]
	})
	fmt.Printf("\nAfter: %v", nums)
}

输出

Before: [3 4 2 1]
After: [1 2 3 4]

注意: 查看我们的 Golang 高级教程。该系列教程内容详尽,我们尽力覆盖所有概念并提供示例。这个教程适合那些希望获得专业知识和扎实理解 Golang 的人 - Golang 高级教程

如果你有兴趣了解所有设计模式如何在 Golang 中实现。如果是的话,这篇文章就是为你准备的 -

所有设计模式 Golang

注意: 查看我们的系统设计教程系列 系统设计问题

在 Go 中对字符串进行排序(Golang)

来源:golangbyexample.com/sort-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))

因此,为了对字符串进行排序,我们需要将其转换为 rune 数组,然后使用 Go 的sort.Sort函数对其进行排序。

以下是sort.Sort函数的签名

func Sort(data Interface)

这里是接口的定义

type Interface interface {
	// Len is the number of elements in the collection.
	Len() int

	// Less reports whether the element with index i
	// must sort before the element with index j.
	Less(i, j int) bool

	// Swap swaps the elements with indexes i and j.
	Swap(i, j int)
}

因此,无论我们想用sort.Sort函数排序什么,都需要实现上述三个函数。

  • Len() int

  • Less(i, j int) bool

  • Swap(i, j int)

在下面的程序中,我们做了同样的事情

package main

import (
	"fmt"
	"sort"
)

func main() {
	sortString("bac")
}

func sortString(input string) {
	runeArray := []rune(input)
	sort.Sort(sortRuneString(runeArray))
	fmt.Println(string(runeArray))
}

type sortRuneString []rune

func (s sortRuneString) Swap(i, j int) {
	s[i], s[j] = s[j], s[i]
}

func (s sortRuneString) Less(i, j int) bool {
	return s[i] < s[j]
}

func (s sortRuneString) Len() int {
	return len(s)
}

输出

abc

注意: 请查看我们的 Golang 高级教程。本系列教程内容详尽,我们尽力涵盖所有概念并附上示例。本教程适合那些希望获得专业知识和扎实理解 Golang 的读者 - Golang 高级教程

如果你有兴趣了解所有设计模式如何在 Golang 中实现。如果是的话,那么这篇文章适合你 - 所有设计模式 Golang

在 Go 中对 0、1 和 2 的数组进行排序。

来源:golangbyexample.com/sort-array-one-zero-two-golang/

目录

  • 概述

  • 第一种方法 - 使用计数

  • 第二种方法 - 使用交换和洗牌

概述

目标是对一个包含 0、1 和 2 的数组进行排序,使所有的 0 在开头,所有的 1 在中间,所有的 2 在最后。该解决方案的空间复杂度应为 O(1),这意味着不应在给定数组的输入大小上分配任何额外空间。

例如

Input: [0, 1, 2, 0, 1]
Output: [0, 0, 1, 1, 2]

Input: [1, 0]
Output: [0, 1]

解决此问题有两种方法。

第一种方法:我们可以遍历数组并记录 0、1 和 2 的数量。一旦我们有了计数,再次遍历数组并将该数量的 0 先放入,然后是 1 的数量,最后是 2 的数量。

第二种方法:在第二种方法中,我们可以使用三个索引。

  • low 初始化为 0。

  • mid 初始化为 0。

  • high 初始化为输入数组长度减一。

现在遍历数组的 mid 位置。

  • 如果遇到 0,我们将其移动到位置low的左侧。然后递增lowmid

  • 如果遇到 1,我们简单地执行mid++

  • 如果遇到 2,我们将其简单地移动到位置high的右侧。然后递减high

这里是相同的程序。

第一种方法 - 使用计数

package main

import "fmt"

func main() {
	sortNums([]int{2, 0, 2, 1, 1, 0})
}

func sortNums(nums []int) {
	zeroCount := 0
	oneCount := 0
	twoCount := 0

	for i := 0; i < len(nums); i++ {
		switch nums[i] {
		case 0:
			zeroCount++
		case 1:
			oneCount++
		case 2:
			twoCount++
		}
	}
	counter := 0
	for i := 0; i < zeroCount; i++ {
		nums[counter] = 0
		counter++
	}
	for i := 0; i < oneCount; i++ {
		nums[counter] = 1
		counter++
	}
	for i := 0; i < twoCount; i++ {
		nums[counter] = 2
		counter++
	}
	fmt.Println(nums)
}

输出

[0 0 1 1 2 2]

第二种方法 - 使用交换和洗牌

package main

import "fmt"

func main() {
	sortNums([]int{2, 0, 2, 1, 1, 0})
}

func sortNums(nums []int) {
	low := 0
	mid := 0
	high := len(nums) - 1

	for mid <= high {

		switch nums[mid] {
		case 0:
			nums[low], nums[mid] = nums[mid], nums[low]
			low++
			mid++
		case 1:
			mid++
		case 2:
			nums[mid], nums[high] = nums[high], nums[mid]
			high--
		}
	}
	fmt.Println(nums)
}

输出

[0 0 1 1 2 2]

注意:查看我们的 Golang 高级教程。本系列的教程内容详尽,我们尝试涵盖所有概念并配有示例。该教程适合那些希望获得专业知识并深入理解 Golang 的人 - Golang 高级教程

如果你有兴趣了解所有设计模式如何在 Golang 中实现。如果是,那么这篇文章就是为你准备的 - 所有设计模式 Golang

在 Go (Golang)中按频率对字符进行排序

来源:golangbyexample.com/sort-characters-frequency-go/

目录

  • 概述

  • 程序

概述

给定一个输入字符串。目标是根据频率对字符串进行排序。我们必须按照字符频率的降序进行排序。让我们通过一个示例来理解

示例 1

Input: "bcabcb"
Output: "bbbcca"

示例 2

Input: "mniff"
Output: "ffmni"

程序

下面是相同的程序

package main

import (
	"fmt"
	"sort"
)

func frequencySort(s string) string {
	stringMap := make(map[byte]int)
	lenS := len(s)
	for i := 0; i < lenS; i++ {
		stringMap[s[i]]++
	}

	itemArray := make([]item, 0)

	for key, value := range stringMap {
		i := item{
			char:      key,
			frequency: value,
		}
		itemArray = append(itemArray, i)
	}

	sort.Slice(itemArray, func(i, j int) bool {
		return itemArray[i].frequency > itemArray[j].frequency
	})

	output := ""

	for i := 0; i < len(itemArray); i++ {
		for j := 0; j < itemArray[i].frequency; j++ {
			output = output + string(itemArray[i].char)
		}
	}

	return output

}

type item struct {
	char      byte
	frequency int
}

func main() {
	output := frequencySort("bcabcb")
	fmt.Println(output)

	output = frequencySort("mniff")
	fmt.Println(output)

}

输出:

bbbcca
ffmni

注意: 请查看我们的 Golang 高级教程。本系列教程详细且覆盖了所有概念及示例。本教程适合那些希望获得专业知识并深入理解 Golang 的学习者 - Golang 高级教程

如果你对了解所有设计模式在 Golang 中的实现感兴趣,这篇文章适合你 - 所有设计模式 Golang

同时,请查看我们的系统设计教程系列 - 系统设计教程系列

将已排序数组转换为高度平衡的 BST(Golang)。

来源:golangbyexample.com/sorted-array-balanced-bst-golang/

目录

  • 概述

  • 程序

概述

给定一个已排序的数组。数组按升序排序。目标是将该已排序数组转换为高度平衡的 BST。

平衡 BST 是指每个节点的左子树和右子树的高度差最大为 1 的 BST。

程序

这里是相同程序的代码。

package main

import "fmt"

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

func sortedArrayToBST(nums []int) *TreeNode {
	length := len(nums)
	return sortedArrayToBSTUtil(nums, 0, length-1)
}

func sortedArrayToBSTUtil(nums []int, first int, last int) *TreeNode {

	if first > last {
		return nil
	}

	if first == last {
		return &TreeNode{
			Val: nums[first],
		}
	}

	mid := (first + last) / 2

	root := &TreeNode{
		Val: nums[mid],
	}

	root.Left = sortedArrayToBSTUtil(nums, first, mid-1)
	root.Right = sortedArrayToBSTUtil(nums, mid+1, last)
	return root
}

func traverseInorder(root *TreeNode) {
	if root == nil {
		return
	}

	traverseInorder(root.Left)
	fmt.Println(root.Val)
	traverseInorder(root.Right)
}

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

}

输出

1
2
3
4
5

注意: 请查看我们的 Golang 高级教程。此系列的教程内容详尽,我们尝试涵盖所有概念并附带示例。此教程适合那些希望获得专业知识和对 golang 有扎实理解的读者——Golang 高级教程

如果你有兴趣了解如何在 Golang 中实现所有设计模式。如果是的话,那么这篇文章适合你——所有设计模式 Golang

Go 语言中的螺旋矩阵问题

来源:golangbyexample.com/spiral-matrix-problem-golang/

目录

  • 概述

  • 程序

概述

目标是以螺旋格式打印矩阵。

例如

输入

1, 2, 3 
4, 5, 6 
7, 8, 9

输出

1 2 3 6 9 8 7 4 5

程序

以下是相应的程序

package main

import "fmt"

func main() {
	matrix := [][]int{{1, 2, 3}, {4, 5, 6}, {7, 8, 9}}
	output := spiralOrder(matrix)
	fmt.Println(output)

	matrix = [][]int{{1, 2, 3, 4}, {5, 6, 7, 8}, {9, 10, 11, 12}, {13, 14, 15, 16}}
	output = spiralOrder(matrix)
	fmt.Println(output)
}

func spiralOrder(matrix [][]int) []int {

	var output []int
	totalRows := len(matrix)
	totalColumns := len(matrix[0])

	startRow := 0
	endRow := totalRows - 1
	startColumn := 0
	endColumn := totalColumns - 1

	for startRow <= endRow && startColumn <= endColumn {

		for i := startColumn; i <= endColumn; i++ {
			output = append(output, matrix[startRow][i])
		}

		startRow++

		for i := startRow; i <= endRow; i++ {
			output = append(output, matrix[i][endColumn])
		}

		endColumn--

		if startRow <= endRow {
			for i := endColumn; i >= startColumn; i-- {
				output = append(output, matrix[endRow][i])
			}
		}

		endRow--

		if startColumn <= endColumn {
			for i := endRow; i >= startRow; i-- {
				output = append(output, matrix[i][startColumn])
			}
		}
		startColumn++
	}

	return output

}

输出

[1 2 3 6 9 8 7 4 5]
[1 2 3 4 8 12 16 15 14 13 9 5 6 7 11 10]

注意: 查看我们的 Golang 高级教程。本系列教程内容详尽,我们尽量用例子覆盖所有概念。这个教程适合那些希望获得专业知识和对 golang 有深入理解的读者——Golang 高级教程

如果你有兴趣了解所有设计模式如何在 Golang 中实现,那么这篇文章就是为你准备的——所有设计模式 Golang

在 Go(Golang)中拆分字符串

来源:golangbyexample.com/split-a-string-golang/

目录

  • 概述

  • 代码

概述

在 Golang 中,字符串是 UTF-8 编码的。GO 的strings包提供了一个可以根据分隔符拆分字符串的Split方法。

以下是该函数的签名:

func Split(s, sep string) []string

正如你所注意到的,Split函数的返回值是一个字符串切片。让我们注意一下这个方法的几点。

  • 案例 1:Split方法将s拆分成由sep分隔的子字符串。它将返回一个字符串切片。

  • 案例 2:如果s不包含sep,则返回一个长度为 1 的字符串切片。这个切片的唯一元素将是s

  • 案例 3:如果sep为空,则会在将s拆分为每个 UTF-8 序列后返回一个字符串切片。

  • 案例 4:如果ssep都为空,它将返回一个空的字符串切片。

代码

package main

import (
    "fmt"
    "strings"
)

func main() {
    //Case 1 s contains sep. Will output slice of length 3
    res := strings.Split("ab$cd$ef", "$")
    fmt.Println(res)

    //Case 2 s doesn't contain sep. Will output slice of length 1
    res = strings.Split("ab$cd$ef", "-")
    fmt.Println(res)

    //Case 3 sep is empty. Will output slice of length 8
    res = strings.Split("ab$cd$ef", "")
    fmt.Println(res)

    //Case 4 both s and sep are empty. Will output empty slice
    res = strings.Split("", "")
    fmt.Println(res)
}

输出:

[ab cd ef]
[ab$cd$ef]
[a b $ c d $ e f]
[]
```*


<!--yml

category: 未分类

date: 2024-10-13 06:15:11

-->

# 在 Go (Golang) 中的平方根

> 来源:[`golangbyexample.com/square-root-number-golang/`](https://golangbyexample.com/square-root-number-golang/)

目录

+   概述

+   代码:

# **概述**

GO 的**math**包提供了一个**Sqrt**方法,可以用来获取该数字的立方根。

以下是该函数的签名。它接受一个浮点数输入,并返回一个浮点数。

```go
func Sqrt(x float64) float64

Sqrt 函数的一些特殊情况是

  • Sqrt(±0) = ±0

  • Sqrt(±Inf) = ±Inf

  • Sqrt(x < 0) = NaN

  • Sqrt(NaN) = NaN

代码:

package main

import (
	"fmt"
	"math"
)

func main() {
	//Square root of a integer
	res := math.Sqrt(4)
	fmt.Println(res)

	//Square root of a integer
	res = math.Sqrt(9)
	fmt.Println(res)

	//Square Root of a float
	res = math.Sqrt(30.33)
	fmt.Println(res)

	//Square Root of a negative number
	res = math.Sqrt(-9)
	fmt.Println(res)
} 

输出:

2
3
5.5072679252057455

Go 中的栈

来源:golangbyexample.com/stack-in-golang/

目录

** 介绍

  • 列表实现

  • 切片实现

介绍

一个简单的栈可以在 Go 中通过

  1. container/list 包

  2. 切片实现

栈将有以下操作:

  1. 推入

  2. 弹出

  3. 前端

  4. 大小

列表实现

package main

import (
    "container/list"
    "fmt"
)

type customStack struct {
    stack *list.List
}

func (c *customStack) Push(value string) {
    c.stack.PushFront(value)
}

func (c *customStack) Pop() error {
    if c.stack.Len() > 0 {
        ele := c.stack.Front()
        c.stack.Remove(ele)
    }
    return fmt.Errorf("Pop Error: Stack is empty")
}

func (c *customStack) Front() (string, error) {
    if c.stack.Len() > 0 {
        if val, ok := c.stack.Front().Value.(string); ok {
            return val, nil
        }
        return "", fmt.Errorf("Peep Error: Stack Datatype is incorrect")
    }
    return "", fmt.Errorf("Peep Error: Stack is empty")
}

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

func (c *customStack) Empty() bool {
    return c.stack.Len() == 0
}

func main() {
    customStack := &customStack{
        stack: list.New(),
    }
    fmt.Printf("Push: A\n")
    customStack.Push("A")
    fmt.Printf("Push: B\n")
    customStack.Push("B")
    fmt.Printf("Size: %d\n", customStack.Size())
    for customStack.Size() > 0 {
        frontVal, _ := customStack.Front()
        fmt.Printf("Front: %s\n", frontVal)
        fmt.Printf("Pop: %s\n", frontVal)
        customStack.Pop()
    }
    fmt.Printf("Size: %d\n", customStack.Size())
}

输出:

Push: A
Push: B
Size: 2
Front: B
Pop: B
Front: A
Pop: A
Size: 0

切片实现

package main

import (
    "fmt"
    "sync"
)

type customStack struct {
    stack []string
    lock  sync.RWMutex
}

func (c *customStack) Push(name string) {
    c.lock.Lock()
    defer c.lock.Unlock()
    c.stack = append(c.stack, name)
}

func (c *customStack) Pop() error {
    len := len(c.stack)
    if len > 0 {
        c.lock.Lock()
        defer c.lock.Unlock()
        c.stack = c.stack[:len-1]
        return nil
    }
    return fmt.Errorf("Pop Error: Stack is empty")
}

func (c *customStack) Front() (string, error) {
    len := len(c.stack)
    if len > 0 {
        c.lock.Lock()
        defer c.lock.Unlock()
        return c.stack[len-1], nil
    }
    return "", fmt.Errorf("Peep Error: Stack is empty")
}

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

func (c *customStack) Empty() bool {
    return len(c.stack) == 0
}

func main() {
    customStack := &customStack{
        stack: make([]string, 0),
    }
    fmt.Printf("Push: A\n")
    customStack.Push("A")
    fmt.Printf("Push: B\n")
    customStack.Push("B")
    fmt.Printf("Size: %d\n", customStack.Size())
    for customStack.Size() > 0 {
        frontVal, _ := customStack.Front()
        fmt.Printf("Front: %s\n", frontVal)
        fmt.Printf("Pop: %s\n", frontVal)
        customStack.Pop()
    }
    fmt.Printf("Size: %d\n", customStack.Size())
}

输出:

Push: A
Push: B
Size: 2
Front: B
Pop: B
Front: A
Pop: A
Size: 0

Go 中的状态设计模式

来源:golangbyexample.com/state-design-pattern-go/

注意:如果想了解如何在 GO 中实现所有其他设计模式,请查看此完整参考 – Go 中的所有设计模式 (Golang)

目录

** 定义:

  • 何时使用

  • UML 图

  • 映射

  • 解释:

  • 实际示例:

定义:

状态设计模式是一种基于有限状态机的行为设计模式。我们将以自动售货机的示例来解释状态设计模式。为了简单起见,假设自动售货机只有一种商品。同时,假设自动售货机可以处于四种不同状态。

  1. 有物品

  2. 无物品

  3. itemRequested

  4. 有钱

自动售货机也会有不同的操作。为了简单起见,假设只有四个操作:

  1. 选择物品

  2. 添加物品

  3. 插入钱

  4. 发放物品

何时使用

  • 当对象可以处于多种不同状态时,使用状态设计模式。根据当前请求,对象需要改变其当前状态

    • 在上述示例中,自动售货机可以处于多种不同状态。假设自动售货机处于 itemRequested 状态,当“插入钱”操作完成后,它将转到 有钱 状态。
  • 当一个对象对同一请求有不同响应时,根据当前状态使用。使用状态设计模式将减少许多条件语句。

    • 例如,在自动售货机的情况下,如果用户想购买一件商品,当机器处于 有物品状态 时将继续进行,如果处于 无物品状态 则会拒绝。注意,自动售货机在购买请求时根据是否处于 有物品状态无物品状态 给出两种不同的响应。请注意下面的 vendingMachine.go 文件,它没有任何条件语句。所有逻辑由具体状态实现处理。

UML 图

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

映射

以下表格表示 UML 图中角色与代码中实际实现角色的映射。

上下文 vendingMachine.go
状态接口 state.go
具体状态 1 noItemState.go
具体状态 2 hasItemState.go
具体状态 3 itemRequestedState.go
具体状态 4 hasMoneyState.go

解释:

  • 我们有一个接口“State”,它定义了表示自动售货机上下文中动作的函数签名。以下是这些动作的函数签名

    1. addItem(int) 错误

    2. requestItem() 错误

    3. insertMoney(money int) 错误

    4. dispenseItem() 错误

  • 每个具体状态实现都实现了上述所有 4 个功能,并在这些操作中移动到另一个状态或给出某种响应。

  • 每个具体状态都嵌入了一个指向当前自动售货机对象的指针,以便在该对象上进行状态转换。

现在让我们看看代码

实际示例:

vendingMachine.go

package main

import "fmt"

type vendingMachine struct {
    hasItem       state
    itemRequested state
    hasMoney      state
    noItem        state

    currentState state

    itemCount int
    itemPrice int
}

func newVendingMachine(itemCount, itemPrice int) *vendingMachine {
    v := &vendingMachine{
        itemCount: itemCount,
        itemPrice: itemPrice,
    }
    hasItemState := &hasItemState{
        vendingMachine: v,
    }
    itemRequestedState := &itemRequestedState{
        vendingMachine: v,
    }
    hasMoneyState := &hasMoneyState{
        vendingMachine: v,
    }
    noItemState := &noItemState{
        vendingMachine: v,
    }

    v.setState(hasItemState)
    v.hasItem = hasItemState
    v.itemRequested = itemRequestedState
    v.hasMoney = hasMoneyState
    v.noItem = noItemState
    return v
}

func (v *vendingMachine) requestItem() error {
    return v.currentState.requestItem()
}

func (v *vendingMachine) addItem(count int) error {
    return v.currentState.addItem(count)
}

func (v *vendingMachine) insertMoney(money int) error {
    return v.currentState.insertMoney(money)
}

func (v *vendingMachine) dispenseItem() error {
    return v.currentState.dispenseItem()
}

func (v *vendingMachine) setState(s state) {
    v.currentState = s
}

func (v *vendingMachine) incrementItemCount(count int) {
    fmt.Printf("Adding %d items\n", count)
    v.itemCount = v.itemCount + count
}

state.go

package main

type state interface {
    addItem(int) error
    requestItem() error
    insertMoney(money int) error
    dispenseItem() error
}

noItemState.go

package main

import "fmt"

type noItemState struct {
    vendingMachine *vendingMachine
}

func (i *noItemState) requestItem() error {
    return fmt.Errorf("Item out of stock")
}

func (i *noItemState) addItem(count int) error {
    i.vendingMachine.incrementItemCount(count)
    i.vendingMachine.setState(i.vendingMachine.hasItem)
    return nil
}

func (i *noItemState) insertMoney(money int) error {
    return fmt.Errorf("Item out of stock")
}
func (i *noItemState) dispenseItem() error {
    return fmt.Errorf("Item out of stock")
}

hasItemState.go

package main

import "fmt"

type hasItemState struct {
    vendingMachine *vendingMachine
}

func (i *hasItemState) requestItem() error {
    if i.vendingMachine.itemCount == 0 {
        i.vendingMachine.setState(i.vendingMachine.noItem)
        return fmt.Errorf("No item present")
    }
    fmt.Printf("Item requestd\n")
    i.vendingMachine.setState(i.vendingMachine.itemRequested)
    return nil
}

func (i *hasItemState) addItem(count int) error {
    fmt.Printf("%d items added\n", count)
    i.vendingMachine.incrementItemCount(count)
    return nil
}

func (i *hasItemState) insertMoney(money int) error {
    return fmt.Errorf("Please select item first")
}
func (i *hasItemState) dispenseItem() error {
    return fmt.Errorf("Please select item first")
}

itemRequestedState.go

package main

import "fmt"

type itemRequestedState struct {
    vendingMachine *vendingMachine
}

func (i *itemRequestedState) requestItem() error {
    return fmt.Errorf("Item already requested")
}

func (i *itemRequestedState) addItem(count int) error {
    return fmt.Errorf("Item Dispense in progress")
}

func (i *itemRequestedState) insertMoney(money int) error {
    if money < i.vendingMachine.itemPrice {
        fmt.Errorf("Inserted money is less. Please insert %d", i.vendingMachine.itemPrice)
    }
    fmt.Println("Money entered is ok")
    i.vendingMachine.setState(i.vendingMachine.hasMoney)
    return nil
}

func (i *itemRequestedState) dispenseItem() error {
    return fmt.Errorf("Please insert money first")
}

hasMoneyState.go

package main

import "fmt"

type hasMoneyState struct {
    vendingMachine *vendingMachine
}

func (i *hasMoneyState) requestItem() error {
    return fmt.Errorf("Item dispense in progress")
}

func (i *hasMoneyState) addItem(count int) error {
    return fmt.Errorf("Item dispense in progress")
}

func (i *hasMoneyState) insertMoney(money int) error {
    return fmt.Errorf("Item out of stock")
}

func (i *hasMoneyState) dispenseItem() error {
    fmt.Println("Dispensing Item")
    i.vendingMachine.itemCount = i.vendingMachine.itemCount - 1
    if i.vendingMachine.itemCount == 0 {
        i.vendingMachine.setState(i.vendingMachine.noItem)
    } else {
        i.vendingMachine.setState(i.vendingMachine.hasItem)
    }
    return nil
}

main.go

package main

import (
    "fmt"
    "log"
)

func main() {
    vendingMachine := newVendingMachine(1, 10)
    err := vendingMachine.requestItem()
    if err != nil {
        log.Fatalf(err.Error())
    }
    err = vendingMachine.insertMoney(10)
    if err != nil {
        log.Fatalf(err.Error())
    }
    err = vendingMachine.dispenseItem()
    if err != nil {
        log.Fatalf(err.Error())
    }

    fmt.Println()
    err = vendingMachine.addItem(2)
    if err != nil {
        log.Fatalf(err.Error())
    }

    fmt.Println()

    err = vendingMachine.requestItem()
    if err != nil {
        log.Fatalf(err.Error())
    }

    err = vendingMachine.insertMoney(10)
    if err != nil {
        log.Fatalf(err.Error())
    }

    err = vendingMachine.dispenseItem()
    if err != nil {
        log.Fatalf(err.Error())
    }
}

输出:

Item requestd
Money entered is ok
Dispensing Item

Adding 2 items

Item requestd
Money entered is ok
Dispensing Item

Go(Golang)中的策略设计模式

来源:golangbyexample.com/strategy-design-pattern-golang/

注意:有兴趣了解其他所有设计模式如何在 GO 中实现吗?请查看这个完整的参考 – Go(Golang)中的所有设计模式

目录

** 定义:

  • 何时使用

  • UML 图

  • 映射

  • 实用例子

定义:

策略设计模式是一种行为设计模式。该设计模式允许你在运行时更改对象的行为,而无需更改该对象的类。

让我们通过一个例子理解策略模式。假设你正在构建一个内存缓存。由于它是内存缓存,因此其大小有限。当它达到最大大小时,需要驱逐一些旧条目。驱逐可以通过几种算法进行。一些流行的算法包括

  1. LRU – 最近最少使用:移除最近最少使用的条目。

  2. FIFO – 先进先出:移除第一个创建的条目。

  3. LFU – 最少使用:移除使用频率最低的条目。

现在的问题是如何将我们的 Cache 类与算法解耦,以便我们能够在运行时更改算法。同时,在添加新算法时,Cache 类也不应改变。这就是策略模式发挥作用的地方。策略模式建议创建一组算法,每个算法都有自己的类。这些类遵循相同的接口,这使得算法在这个家族中是可以互换的。假设通用接口的名称是 evictionAlgo

现在我们的主要 Cache 类将嵌入 evictionAlgo 接口。我们的缓存类不会在内部实现所有类型的驱逐算法,而是将所有任务委托给 evictionAlgo 接口。由于 evictionAlgo 是一个接口,我们可以在运行时将算法更改为 LRU、FIFO 或 LFU,而无需修改 Cache 类。

何时使用

  • 当一个对象需要支持不同的行为,并且你希望在运行时更改该行为时。

  • 当你想避免大量选择运行时行为的条件语句时。

  • 当你有不同的算法,它们相似但仅在执行某些行为的方式上有所不同时。

UML 图

注意下面的 UML 图,上下文(Cache)嵌入了策略(evictionAlgo)接口。

下面是与上述示例相对应的 UML 图

映射

以下表格表示 UML 图中的参与者与代码中实际实现参与者的映射。

上下文 cache.go
策略 evictionAlgo.go
具体策略对象 1 lfu.go
具体策略对象 2 lru.go
具体策略对象 3 fifo.go
客户端 main.go

实际示例

evictionAlgo.go

package main

type evictionAlgo interface {
    evict(c *cache)
}

fifo.go

package main

import "fmt"

type fifo struct {
}

func (l *fifo) evict(c *cache) {
    fmt.Println("Evicting by fifo strtegy")
}

lru.go

package main

import "fmt"

type lru struct {
}

func (l *lru) evict(c *cache) {
    fmt.Println("Evicting by lru strtegy")
}

lfu.go

package main

import "fmt"

type lfu struct {
}

func (l *lfu) evict(c *cache) {
    fmt.Println("Evicting by lfu strtegy")
}

cache.go

package main

type cache struct {
    storage      map[string]string
    evictionAlgo evictionAlgo
    capacity     int
    maxCapacity  int
}

func initCache(e evictionAlgo) *cache {
    storage := make(map[string]string)
    return &cache{
        storage:      storage,
        evictionAlgo: e,
        capacity:     0,
        maxCapacity:  2,
    }
}

func (c *cache) setEvictionAlgo(e evictionAlgo) {
    c.evictionAlgo = e
}

func (c *cache) add(key, value string) {
    if c.capacity == c.maxCapacity {
        c.evict()
    }
    c.capacity++
    c.storage[key] = value
}

func (c *cache) get(key string) {
    delete(c.storage, key)
}

func (c *cache) evict() {
    c.evictionAlgo.evict(c)
    c.capacity--
}

main.go

package main

func main() {
    lfu := &lfu{}
    cache := initCache(lfu)
    cache.add("a", "1")
    cache.add("b", "2")
    cache.add("c", "3")
    lru := &lru{}
    cache.setEvictionAlgo(lru)
    cache.add("d", "4")
    fifo := &fifo{}
    cache.setEvictionAlgo(fifo)
    cache.add("e", "5")
}

输出:

Evicting by lfu strtegy
Evicting by lru strtegy
Evicting by fifo strtegy

Go (Golang) 中的字符串比较

来源:golangbyexample.com/compare-two-strings-golang/

目录

  • 概述

  • 代码:

概述

在 Golang 中,字符串是 UTF-8 编码的。GO 的strings包提供了一个Compare方法,可以用来比较 Go 中的两个字符串。请注意,这个方法是按字典顺序比较字符串的。

以下是该函数的签名

func Compare(a, b string) int

正如您所注意到的,Compare 函数的返回值是一个整数。这个值将是

  • 如果 a==b 则返回 0

  • 如果 a < b 则返回 -1

  • 如果 a > b 则返回 +1

因此,如果返回值为 0,则两个字符串相等。让我们来看一个工作程序。

代码:

package main

import (
    "fmt"
    "strings"
)

func main() {
    res := strings.Compare("abc", "abc")
    fmt.Println(res)

    res = strings.Compare("abc", "xyz")
    fmt.Println(res)

    res = strings.Compare("xyz", "abc")
    fmt.Println(res)
}

输出:

0
-1
1
posted @ 2024-10-19 08:37  绝不原创的飞龙  阅读(0)  评论(0编辑  收藏  举报