通过示例学习-Go-语言-2023-三十二-
通过示例学习 Go 语言 2023(三十二)
Go(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) 中的结构体切片
目录
-
概述
-
程序
概述
在 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)中的布尔切片或数组
目录
-
概述
-
布尔切片
-
布尔数组
概述
在 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)中的通道切片或数组
目录
概述
-
通道切片
-
通道数组
概述
在 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)中排序部分切片
概述
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)中以升序和降序排序整型切片
目录
** 以升序排序切片
- 以降序排序切片
以升序排序切片
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方法。
下面是该方法的签名。
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 中实现。如果是的话,这篇文章就是为你准备的 -
注意: 查看我们的系统设计教程系列 系统设计问题
在 Go 中对字符串进行排序(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 的数组进行排序。
目录
-
概述
-
第一种方法 - 使用计数
-
第二种方法 - 使用交换和洗牌
概述
目标是对一个包含 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的左侧。然后递增low和mid。
-
如果遇到 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)中按频率对字符进行排序
目录
-
概述
-
程序
概述
给定一个输入字符串。目标是根据频率对字符串进行排序。我们必须按照字符频率的降序进行排序。让我们通过一个示例来理解
示例 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)。
目录
-
概述
-
程序
概述
给定一个已排序的数组。数组按升序排序。目标是将该已排序数组转换为高度平衡的 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 语言中的螺旋矩阵问题
目录
-
概述
-
程序
概述
目标是以螺旋格式打印矩阵。
例如
输入
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)中拆分字符串
目录
-
概述
-
代码
概述
在 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:如果s和sep都为空,它将返回一个空的字符串切片。
代码
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 中的栈
目录
** 介绍
-
列表实现
-
切片实现
介绍
一个简单的栈可以在 Go 中通过
-
container/list 包
-
切片实现
栈将有以下操作:
-
推入
-
弹出
-
前端
-
大小
-
空
列表实现
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 中的状态设计模式
注意:如果想了解如何在 GO 中实现所有其他设计模式,请查看此完整参考 – Go 中的所有设计模式 (Golang)
目录
** 定义:
-
何时使用
-
UML 图
-
映射
-
解释:
-
实际示例:
定义:
状态设计模式是一种基于有限状态机的行为设计模式。我们将以自动售货机的示例来解释状态设计模式。为了简单起见,假设自动售货机只有一种商品。同时,假设自动售货机可以处于四种不同状态。
-
有物品
-
无物品
-
itemRequested
-
有钱
自动售货机也会有不同的操作。为了简单起见,假设只有四个操作:
-
选择物品
-
添加物品
-
插入钱
-
发放物品
何时使用
-
当对象可以处于多种不同状态时,使用状态设计模式。根据当前请求,对象需要改变其当前状态
- 在上述示例中,自动售货机可以处于多种不同状态。假设自动售货机处于 itemRequested 状态,当“插入钱”操作完成后,它将转到 有钱 状态。
-
当一个对象对同一请求有不同响应时,根据当前状态使用。使用状态设计模式将减少许多条件语句。
- 例如,在自动售货机的情况下,如果用户想购买一件商品,当机器处于 有物品状态 时将继续进行,如果处于 无物品状态 则会拒绝。注意,自动售货机在购买请求时根据是否处于 有物品状态 或 无物品状态 给出两种不同的响应。请注意下面的 vendingMachine.go 文件,它没有任何条件语句。所有逻辑由具体状态实现处理。
UML 图
映射
以下表格表示 UML 图中角色与代码中实际实现角色的映射。
上下文 | vendingMachine.go |
---|---|
状态接口 | state.go |
具体状态 1 | noItemState.go |
具体状态 2 | hasItemState.go |
具体状态 3 | itemRequestedState.go |
具体状态 4 | hasMoneyState.go |
解释:
-
我们有一个接口“State”,它定义了表示自动售货机上下文中动作的函数签名。以下是这些动作的函数签名
-
addItem(int) 错误
-
requestItem() 错误
-
insertMoney(money int) 错误
-
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)中的策略设计模式
注意:有兴趣了解其他所有设计模式如何在 GO 中实现吗?请查看这个完整的参考 – Go(Golang)中的所有设计模式
目录
** 定义:
-
何时使用
-
UML 图
-
映射
-
实用例子
定义:
策略设计模式是一种行为设计模式。该设计模式允许你在运行时更改对象的行为,而无需更改该对象的类。
让我们通过一个例子理解策略模式。假设你正在构建一个内存缓存。由于它是内存缓存,因此其大小有限。当它达到最大大小时,需要驱逐一些旧条目。驱逐可以通过几种算法进行。一些流行的算法包括
-
LRU – 最近最少使用:移除最近最少使用的条目。
-
FIFO – 先进先出:移除第一个创建的条目。
-
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 * 策略设计模式 * Golang 中的策略设计模式 *
Go (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