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

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

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

用 Go 語言編寫的所得稅計算程式

來源:golangbyexample.com/income-tax-bracket-program-golang/

目錄

  • 概述

  • 程式

概述

給定一個二維陣列,表示所得稅的稅率區間。輸入陣列為稅率區間,其中

brackets[i] = [upperi, percenti]

這意味著第 i 個區間的上限為upperi,稅率為percent。 稅率區間陣列按上限排序。以下是計算稅率的方法

  • upper0 以下的金額稅率為 percent0

  • upper1-upper0 的稅率為 percent1

  • .. 以此類推

你還需要輸入收入。你需要計算該收入的所得稅。已知最後一個區間的上限大於收入。

示例 1

Input: brackets = [[4,10],[9,20],[12,30]], income = 10
Output: 1.7

示例 2

Input: brackets = [[3,10]], income = 1
Output: 0.3

程式

下面是該程式的內容

package main

import "fmt"

func calculateTax(brackets [][]int, income int) float64 {
	if income == 0 {
		return 0
	}

	var totalTax float64

	numBrackets := len(brackets)
	upper := 0
	for i := 0; i < numBrackets; i++ {

		if i == 0 {
			upper = brackets[i][0]
		} else {
			upper = brackets[i][0] - brackets[i-1][0]
		}

		taxPer := brackets[i][1]
		if income <= upper {
			totalTax += float64(income) * float64(taxPer) / 100
			break
		} else {
			totalTax += float64(upper) * float64(taxPer) / 100
			income = income - upper
		}
	}

	return totalTax
}

func main() {
	output := calculateTax([][]int{{4, 10}, {9, 20}, {12, 30}}, 10)
	fmt.Println(output)

	output = calculateTax([][]int{{3, 10}}, 10)
	fmt.Println(output)

}

輸出:

1.7
0.3

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

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

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

計算字串中最後一個單詞長度的 Go 程式 (Golang)

來源:golangbyexample.com/length-last-word-golang/

目錄

  • 概述

  • 程式

概述

目標是找到給定字串中最後一個單詞的長度

示例

Input: "computer science"
Output: 7

The last word is science and its length is 7

Input: "computer science is a subject "
Output: 7

The last word is subject and ts length is 7

Input: " "
Output: 0

There is no last word hence answer is zero

程式

下面是相應的程式。

package main

import "fmt"

func lengthOfLastWord(s string) int {
	lenS := len(s)

	lenLastWord := 0
	for i := lenS - 1; i >= 0; {
		for i >= 0 && string(s[i]) == " " {
			i--
		}
		if i < 0 {
			return 0
		}

		for i >= 0 && string(s[i]) != " " {
			//fmt.Println(i)
			//fmt.Println(string(s[i]))
			i--
			lenLastWord++
		}

		return lenLastWord
	}

	return 0
}

func main() {
	length := lengthOfLastWord("computer science")
	fmt.Println(length)

	length = lengthOfLastWord("computer science is a subject")
	fmt.Println(length)

	length = lengthOfLastWord("  ")
	fmt.Println(length)
}

輸出

7
7
0

注意: 檢視我們的 Golang 高階教程。該系列教程詳細而全面,我們嘗試用示例覆蓋所有概念。本教程適合那些希望獲得專業知識和紮實理解 Golang 的人 – Golang 高階教程

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

透過刪除在 Go (Golang) 中查詢字典中最長單詞的程式

來源:golangbyexample.com/longest-word-dictionary-go/

目錄

  • 概述

  • 程式

概述

給定一個字串和一個單詞字典。目標是找到字典中作為子序列出現在給定字串中的最長單詞。如果可能的結果數量超過 1,則返回字典中按字典順序最小的最長單詞。

示例 1

s = "mbacnago", dictionary = ["ale","mango","monkey","plea"]
Output: "mango"

示例 2

s = "mbacnago", dictionary = ["ba","ag"]
Output: "ag"

程式

下面是相同的程式

package main

import (
	"fmt"
	"sort"
)

func findLongestWord(s string, dictionary []string) string {
	sort.Slice(dictionary, func(i, j int) bool {
		lenI := len(dictionary[i])
		lenJ := len(dictionary[j])

		if lenI == lenJ {
			return dictionary[i] < dictionary[j]
		}

		return lenI > lenJ
	})

	lenS := len(s)

	for i := 0; i < len(dictionary); i++ {
		if isSubstring(s, dictionary[i], lenS) {
			return dictionary[i]
		}
	}

	return ""
}

func isSubstring(s string, sub string, lenS int) bool {
	lenSub := len(sub)

	if lenSub == 0 {
		return true
	}

	if lenSub > lenS {
		return false
	}

	for i, j := 0, 0; i < lenS && j < lenSub; {
		if i+lenSub-j-1 >= lenS {
			return false
		}
		if s[i] == sub[j] {
			j++
		}
		if j == lenSub {
			return true
		}
		i++
	}

	return false
}

func main() {
	output := findLongestWord("mbacnago", []string{"ale", "mango", "monkey", "plea"})
	fmt.Println(output)

	output = findLongestWord("mbacnago", []string{"ba", "ag"})
	fmt.Println(output)

}

輸出

mango
ag

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

如果你對理解所有設計模式在 Golang 中的實現感興趣,那麼這篇文章適合你 – 所有設計模式 Golang

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

Go (Golang) 中的帕斯卡三角形程式

來源:golangbyexample.com/program-pascal-triangle-golang/

目錄

  • 概述

  • 程式

概述

目標是列印 n 行帕斯卡三角形。數字 n 作為輸入提供給程式

示例 1

Input: numRows = 4
Output: [[1],[1,1],[1,2,1],[1,3,3,1]]

示例 2

Input: numRows = 5
Output: [[1],[1,1],[1,2,1],[1,3,3,1],[1,4,6,4,1]]

請參考此連結以瞭解更多關於帕斯卡三角形的資訊 - en.wikipedia.org/wiki/Pascal%27s_triangle

這裡的思路是使用動態規劃。

程式

以下是相同的程式

package main

import "fmt"

func generate(numRows int) [][]int {
	firstRow := []int{1}

	if numRows == 1 {
		return [][]int{firstRow}
	}

	secondRow := []int{1, 1}

	if numRows == 2 {
		return [][]int{firstRow, secondRow}
	}

	output := [][]int{firstRow, secondRow}

	for i := 2; i < numRows; i++ {
		temp := make([]int, i+1)

		lastRow := output[i-1]

		temp[0] = 1
		temp[i] = 1

		for j := 1; j < i; j++ {
			temp[j] = lastRow[j-1] + lastRow[j]
		}

		output = append(output, temp)

	}

	return output

}

func main() {
	output := generate(4)
	fmt.Println(output)

	output = generate(5)
	fmt.Println(output)
}

輸出:

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

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

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

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

用 Go (Golang)編寫的給定整數陣列的冪集程式。

來源:golangbyexample.com/power-set-array-golang/

目錄

概述

  • 程式

概述

給定一個包含所有唯一元素的整數陣列。目標是返回該陣列的冪集。

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

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

如果給定陣列中的元素數量為 n,則冪集中的元素數量將為 pow(2, n)。假設 n 為 3,則冪集中的元素數量為 pow(2, n)=8。

假設我們對數字從 0 到(8-1)進行所有二進位制轉換,即從 0 到 7。

000
001
010
011
100
101
110
111

上面的每個二進位制數字表示一個冪集。

例如

000 - []
001 - [1]
010 - [2]
011 - [1, 2]
100 - [3]
101 - [1, 3]
110 - [2, 3]
111 - [1, 2, 3]

程式

這是相應的程式。

package main

import (
	"fmt"
	"math"
)

func subsets(nums []int) [][]int {

	lengthNums := len(nums)
	powerSetLength := int(math.Pow(2, float64(lengthNums)))
	output := make([][]int, 0)

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

		result := make([]int, 0)
		for j := 0; j < lengthNums; j++ {
			val := int(i) & int(1<

輸出

[[] [1] [2] [1 2]]
[[] [1] [2] [1 2] [3] [1 3] [2 3] [1 2 3]]

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

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

Go(Golang)中的相同二叉樹程式

來源:golangbyexample.com/same-binary-tree-golang/

目錄

  • 概述

  • 程式

概述

目標是檢查給定的兩棵二叉樹是否相同。以下樹是相同的

樹 1

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

樹 2

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

程式

這裡是相同的程式。

package main

import (
	"fmt"
)

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

func isSameTree(p *TreeNode, q *TreeNode) bool {
	if p == nil && q == nil {
		return true
	}

	if p == nil || q == nil {
		return false
	}

	if p.Val != q.Val {
		return false
	}

	return isSameTree(p.Left, q.Left) && isSameTree(p.Right, q.Right)
}

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

	root2 := TreeNode{Val: 1}
	root2.Left = &TreeNode{Val: 2}
	root2.Left.Left = &TreeNode{Val: 4}
	root2.Right = &TreeNode{Val: 3}
	root2.Right.Left = &TreeNode{Val: 5}
	root2.Right.Right = &TreeNode{Val: 6}

	output := isSameTree(&root1, &root2)
	fmt.Println(output)

	root1 = TreeNode{Val: 1}
	root1.Left = &TreeNode{Val: 2}

	root2 = TreeNode{Val: 1}
	root2.Left = &TreeNode{Val: 3}

	output = isSameTree(&root1, &root2)
	fmt.Println(output)
}

輸出

true
false

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

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

在 Go(Golang)中計算句子中單詞總數的程式

來源:golangbyexample.com/number-words-sentence-golang/

目錄

  • 概述

  • 程式

概述

給定一個句子,找出其中的單詞數量。句子中的每個單詞只包含英語字母。

示例

Input: "Hello World"
Output: 2

Input: "This is hat"
Output: 3

程式

這是相同的程式。

package main

import "fmt"

func countW(s string) int {

	lenS := len(s)
	numWords := 0

	for i := 0; i < lenS; {
		for i < lenS && string(s[i]) == " " {
			i++
		}

		if i < lenS {
			numWords++
		}

		for i < lenS && string(s[i]) != " " {
			i++
		}
	}

	return numWords
}

func main() {
	output := countW("Hello World")
	fmt.Println(output)

	output = countW("This is hat")
	fmt.Println(output)
}

輸出

2
3

注意: 請檢視我們的 Golang 高階教程。該系列教程內容豐富,我們嘗試用例子覆蓋所有概念。本教程適合希望獲得專業知識和對 Golang 有深入理解的人 - Golang 高階教程

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

Go (Golang) 中的醜陋數字 2 的程式

來源:golangbyexample.com/program-for-ugly-number-2-in-go-golang/

目錄

  • 概述

  • 程式

概述

醜陋數字是其質因數限於 2、3 和 5 的數字。我們已經見過一個程式,它給定一個數字 n,返回 true 如果它是醜陋數字,否則返回 false。下面是那個程式的連結 golangbyexample.com/ugly-number-golang/

在本教程中,我們將編寫一個程式,給定一個數字 n,找到第 n 個醜陋數字。

示例 1

Input: 5
Output: 5
Reason: First five ugly numbers are 1, 2, 3, 4, 5 hence 5th ugly number is 5

示例 2

Input: 20
Output: 36

這個想法是使用動態程式設計。我們將跟蹤 2、3 和 5 的倍數。下一個醜陋數字將始終是這三個中的最小值。

程式

以下是相同的程式

package main

import "fmt"

func nthUglyNumber(n int) int {
	dpUgly := make([]int, n)

	dpUgly[0] = 1

	next_multiple_of_2 := 2
	next_multiple_of_3 := 3
	next_multiple_of_5 := 5

	i2 := 0
	i3 := 0
	i5 := 0

	for i := 1; i < n; i++ {
		nextUglyNumber := minOfThree(next_multiple_of_2, next_multiple_of_3, next_multiple_of_5)
		dpUgly[i] = nextUglyNumber

		if nextUglyNumber == next_multiple_of_2 {
			i2++
			next_multiple_of_2 = 2 * dpUgly[i2]
		}

		if nextUglyNumber == next_multiple_of_3 {
			i3++
			next_multiple_of_3 = 3 * dpUgly[i3]
		}

		if nextUglyNumber == next_multiple_of_5 {
			i5++
			next_multiple_of_5 = 5 * dpUgly[i5]
		}

	}

	return dpUgly[n-1]

}

func minOfThree(a, b, c int) int {
	if a < b && a < c {
		return a
	}

	if b < c {
		return b
	}

	return c
}

func main() {
	output := nthUglyNumber(5)
	fmt.Println(output)

	output = nthUglyNumber(20)
	fmt.Println(output)
}

輸出

5
36

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

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

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

在 Go (Golang) 中的醜數程式

來源:golangbyexample.com/ugly-number-golang/

目錄

  • 概述

  • 程式

概述

醜數是其質因數僅限於 2、3 和 5 的數字。

給定一個數字 n,如果它是一個醜數則返回 true,否則返回 false。

示例 1

Input: 12
Output: true

示例 2

Input: 7 
Output: false

思路是

  • 當數字是 2 的因數時,不斷將數字除以 2。

  • 當數字是 3 的因數時,不斷將數字除以 3。

  • 當數字是 5 的因數時,不斷將數字除以 5。

最後,如果數字等於 1,則返回 true,否則返回 false。

程式

以下是相同的程式

package main

import "fmt"

func isUgly(n int) bool {
	if n == 0 {
		return false
	}
	if n == 1 {
		return true
	}

	for {
		if n%2 != 0 {
			break
		}
		n = n / 2
	}

	for {
		if n%3 != 0 {
			break
		}
		n = n / 3
	}

	for {
		if n%5 != 0 {
			break
		}
		n = n / 5
	}

	return n == 1
}

func main() {
	output := isUgly(12)
	fmt.Println(output)

	output = isUgly(7)
	fmt.Println(output)
}

輸出

true
false

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

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

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

在 Go (Golang) 中新增數字的所有數字的程式

來源:golangbyexample.com/add-all-digits-number-golang/

目錄

  • 概述

  • 程式

概述

目標是反覆相加一個數字的所有數字,直到結果僅為一個單一數字。

例如

Input: 453
Step 1: 4+5+3 = 12
Step 2: 1+2 =3

Output: 3

另一個示例

Input: 45
Step 1: 4+5 = 9

Output: 9

程式

這是相同程式的程式碼

package main

import "fmt"

func addDigits(num int) int {

	if num < 10 {
		return num
	}

	for num > 9 {
		num = sum(num)
	}

	return num

}

func sum(num int) int {
	output := 0
	for num > 0 {
		output = output + num%10
		num = num / 10
	}
	return output
}

func main() {
	output := addDigits(453)
	fmt.Println(output)

	output = addDigits(45)
	fmt.Println(output)

}

輸出

3
9

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

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

用 Go(Golang)編寫的計算一個數字的冪的程式。

來源:golangbyexample.com/power-number-golang/

目錄

  • 概述

  • 程式

概述

目標是計算給定整數的冪。將有兩個輸入。

  • 數字本身 – 這個數字可以是正數也可以是負數,也可以是浮點數。

  • 冪 – 冪可以是正數,也可以是負數。

示例

Input: Num:2, Power:4
Output: 16

Input: Num:2, Power:-4
Output: 0.0625

程式

這是相同程式的程式碼。

package main

import "fmt"

func pow(x float64, n int) float64 {

	if x == 0 {
		return 0
	}

	if n == 0 {
		return 1
	}

	if n == 1 {
		return x
	}

	if n == -1 {
		return 1 / x
	}

	val := pow(x, n/2)

	m := x
	if n < 0 {
		m = 1 / x
	}

	if n%2 == 1 || n%2 == -1 {
		return val * val * m
	} else {
		return val * val
	}

}

func main() {
	output := pow(2, 4)
	fmt.Println(output)

	output = pow(2, -4)
	fmt.Println(output)
}

輸出

16
0.0625

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

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

用 Go(Golang)乘兩個字串的程式

來源:golangbyexample.com/multiply-two-strings-golang/

目錄

  • 概述

  • 程式

概述

編寫一個程式來乘兩個字串。

示例

Input: "12"*"12"
Output: 144

Input: "123"*"12"
Output: 1476

程式

這是相應的程式。

package main

import (
	"fmt"
	"math"
	"strconv"
)

func multiply(num1 string, num2 string) string {

	if len(num1) > len(num2) {
		num2, num1 = num1, num2
	}

	output := 0

	k := 0

	carry := 0

	for i := len(num1) - 1; i >= 0; i-- {

		x := 0
		temp := 0
		for j := len(num2) - 1; j >= 0; j-- {

			digit1, _ := strconv.Atoi(string(num1[i]))
			digit2, _ := strconv.Atoi(string(num2[j]))

			multiply_output := digit1*digit2 + carry

			carry = multiply_output / 10

			temp = multiply_output%10*int(math.Pow(10, float64(x))) + temp
			x = x + 1
		}

		temp = carry*int(math.Pow(10, float64(x))) + temp
		carry = 0

		output = temp*int(math.Pow(10, float64(k))) + output
		k = k + 1
	}

	return strconv.Itoa(output)
}

func main() {
	output := multiply("12", "12")
	fmt.Println(output)

	output = multiply("123", "12")
	fmt.Println(output)
}

輸出

144
1476

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

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

協議緩衝與 Go:入門指南

來源:golangbyexample.com/protocol-buffers-go/

在本教程中,我們將看到協議緩衝如何在 GO 語言中使用。

什麼是協議緩衝

協議緩衝是一種以結構化格式儲存資料的資料格式。協議緩衝格式中的資料可以被多種語言序列化和反序列化。

聽起來很混亂。你可以把它理解為 JSON、XML,但它提供了許多優勢。仍然感到困惑嗎?那麼不用擔心,隨著教程的進行,我們將理解為什麼甚至需要一個新的資料格式。

讓我們先看看最簡單的協議緩衝檔案的例子。

person.proto

syntax = "proto3";

message Person {
    string name = 1;
}

關於上述檔案,有幾點需要注意。

  • 這個檔案只是我們協議緩衝結構的藍圖。尚未關聯任何資料。這與 JSON/XML 不同,後者的檔案也表示實際資料。

  • 在上述檔案中,有一個 person 訊息,其欄位 name 的型別為 string。 “proto3” 意味著該訊息與協議緩衝版本三不相容。

  • 從上面的例子可以注意到一個不同之處,即它具有型別資訊。這種型別的資訊在不同語言的程式碼自動生成中將非常有用。讓我們看看在 Golang 中的自動生成示例。

GO 程式碼的自動生成:

  • 我們可以使用上述 person.proto 檔案生成相應的 Golang 程式碼。但為此我們需要進行一些安裝:

安裝:

  • 首先安裝協議緩衝的 C++ 實現。每個平臺的安裝方式各不相同。請參見此連結 – github.com/protocolbuffers/protobuf/blob/master/src/README.md

  • 安裝 Golang

  • 安裝 protoc-gen-go – go get -u github.com/golang/protobuf/protoc-gen-go 這個包將用於 Go 程式碼的自動生成。

安裝完成後,進入包含 person.proto 檔案的目錄。執行此命令:

protoc -I ./ --go_out=./ ./person.proto

它將在同一目錄下生成名為 person.pb.go 的資料訪問 Go 檔案。

// Code generated by protoc-gen-go. DO NOT EDIT.
// source: person.proto

package person

import (
    fmt "fmt"
    proto "github.com/golang/protobuf/proto"
    math "math"
)

// Reference imports to suppress errors if they are not otherwise used.
var _ = proto.Marshal
var _ = fmt.Errorf
var _ = math.Inf

// This is a compile-time assertion to ensure that this generated file
// is compatible with the proto package it is being compiled against.
// A compilation error at this line likely means your copy of the
// proto package needs to be updated.
const _ = proto.ProtoPackageIsVersion3 // please upgrade the proto package

type Person struct {
    Name                 string   `protobuf:"bytes,1,opt,name=name,proto3" json:"name,omitempty"`
    XXX_NoUnkeyedLiteral struct{} `json:"-"`
    XXX_unrecognized     []byte   `json:"-"`
    XXX_sizecache        int32    `json:"-"`
}

func (m *Person) Reset()         { *m = Person{} }
func (m *Person) String() string { return proto.CompactTextString(m) }
func (*Person) ProtoMessage()    {}
func (*Person) Descriptor() ([]byte, []int) {
    return fileDescriptor_4c9e10cf24b1156d, []int{0}
}

func (m *Person) XXX_Unmarshal(b []byte) error {
    return xxx_messageInfo_Person.Unmarshal(m, b)
}
func (m *Person) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) {
    return xxx_messageInfo_Person.Marshal(b, m, deterministic)
}
func (m *Person) XXX_Merge(src proto.Message) {
    xxx_messageInfo_Person.Merge(m, src)
}
func (m *Person) XXX_Size() int {
    return xxx_messageInfo_Person.Size(m)
}
func (m *Person) XXX_DiscardUnknown() {
    xxx_messageInfo_Person.DiscardUnknown(m)
}

var xxx_messageInfo_Person proto.InternalMessageInfo

func (m *Person) GetName() string {
    if m != nil {
        return m.Name
    }
    return ""
}

func init() {
    proto.RegisterType((*Person)(nil), "Person")
}

func init() { proto.RegisterFile("person.proto", fileDescriptor_4c9e10cf24b1156d) }

var fileDescriptor_4c9e10cf24b1156d = []byte{
    // 67 bytes of a gzipped FileDescriptorProto
    0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xe2, 0xe2, 0x29, 0x48, 0x2d, 0x2a,
    0xce, 0xcf, 0xd3, 0x2b, 0x28, 0xca, 0x2f, 0xc9, 0x57, 0x92, 0xe1, 0x62, 0x0b, 0x00, 0xf3, 0x85,
    0x84, 0xb8, 0x58, 0xf2, 0x12, 0x73, 0x53, 0x25, 0x18, 0x15, 0x18, 0x35, 0x38, 0x83, 0xc0, 0xec,
    0x24, 0x36, 0xb0, 0x22, 0x63, 0x40, 0x00, 0x00, 0x00, 0xff, 0xff, 0xa4, 0xaf, 0x53, 0x72, 0x34,
    0x00, 0x00, 0x00,
}

現在最大的問題是,什麼是透過 protoc 使用 person.proto 自動生成的 person.pb.go 檔案。首先要注意幾點。

  • Person 結構體如下。請注意 person.proto 檔案中的型別資訊如何用於瞭解 Name 欄位是字串。
type Person struct {
    Name                 string   `protobuf:"bytes,1,opt,name=name,proto3" json:"name,omitempty"`
    XXX_NoUnkeyedLiteral struct{} `json:"-"`
    XXX_unrecognized     []byte   `json:"-"`
    XXX_sizecache        int32    `json:"-"`
}
  • Person 結構體還實現了一些方法,使其成為介面型別 proto.Message。

基本上,這個自動生成的檔案為 Person 結構體生成資料訪問器,並提供允許將 Person 結構體型別與實際位元組之間進行序列化/反序列化的方法。現在讓我們編寫一個 main.go 程式,實際建立Person結構體的具體物件。在這裡,我們將看到協議緩衝區所提供的幾個優勢。以下程式還展示了 Person 結構體的讀寫操作。

main.go

package main

import (
    "fmt"
    "io/ioutil"
    "log"
    proto "github.com/golang/protobuf/proto"
)

func main() {
    person := &Person{Name: "XXX"}
    fmt.Printf("Person's name is %s\n", person.GetName())

    //Now lets write this person object to file
    out, err := proto.Marshal(person)
    if err != nil {
        log.Fatalf("Serialization error: %s", err.Error())
    }
    if err := ioutil.WriteFile("person.bin", out, 0644); err != nil {
        log.Fatalf("Write File Error: %s ", err.Error())
    }
    fmt.Println("Write Success")

    //Read from file
    in, err := ioutil.ReadFile("person.bin")
    if err != nil {
        log.Fatalf("Read File Error: %s ", err.Error())
    }
    person2 := &Person{}
    err2 := proto.Unmarshal(in, person2)
    if err2 != nil {
        log.Fatalf("DeSerialization error: %s", err.Error())
    }

    fmt.Println("Read Success")
    fmt.Printf("Person2's name is %s\n", person2.GetName())
}

要執行此檔案,首先使用“go get github.com/golang/protobuf/proto”安裝 protobuf/proto,然後使用命令“go run *.go”執行此檔案。輸出:

Person's name is XXX
Write Success
Read Success
Person2's name is XXX

請注意,在上述程式中我們

  • 我們將一個具體的person結構體寫入檔案“person.bin”。這是一個二進位制檔案,不可讀。

  • 我們也從檔案中讀取。能夠成功讀取並列印“Person2 的名字是 XXX”。

“person.bin”檔案的驚人之處在於其僅有 5 個位元組,而如果建立一個相同資料的 JSON 檔案,其大小將超過 15 個位元組。此外,從位元組到具體物件及其反向操作的序列化和反序列化速度也非常快,相比之下,JSON 檔案的序列化和反序列化速度較慢。

現在我們提供了理論。讓我們再一次列出使用協議緩衝區的優勢。

  1. 相比於相應的 JSON 和 XML,更加清晰且不含歧義,因為它們還儲存了型別資訊。

  2. 儲存的資料相對較小,約小 2-3 倍。

  3. 它快得多。例如,使用協議緩衝區的序列化和反序列化速度更快。

  4. 自動程式碼生成——你編寫一個協議緩衝檔案,系統會自動生成相應的 GO 檔案。

  5. 協議緩衝區用於 GRPC,後者是 REST 協議的下一代替代品——請關注此處,我們將很快新增相關文章。

結論: 協議緩衝區提供的內容遠不止我們在文章中討論的。這為協議緩衝區是什麼及其與 JSON/XML 格式相比的優勢提供了快速概述。

  • buffer * go * grpc * protocol * protocolbuffer

Go (Golang)中的原型模式

來源:golangbyexample.com/prototype-pattern-go/

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

目錄

** 定義:

  • 使用時機

  • UML 圖

  • 對映

  • 實際示例:

定義:

這是一種建立型設計模式,允許你建立物件的副本。在此模式中,克隆物件的建立責任委託給實際的克隆物件。

要克隆的物件暴露一個克隆方法,該方法返回物件的克隆副本。

使用時機

  • 當克隆物件的建立過程複雜時,我們使用原型模式,即克隆可能涉及深複製、層次複製等處理。此外,可能還有一些私有成員也無法直接訪問。

  • 建立的是物件的副本,而不是從頭建立一個新例項。這防止了在建立新物件時涉及的昂貴操作,例如資料庫操作。

  • 當你想要建立新物件的副本,但它僅作為介面可用時。因此,你不能直接建立該物件的副本。

UML 圖

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

對映

下表表示 UML 圖中參與者到程式碼中實際實現參與者的對映。

原型介面 inode.go
具體原型 1 file.go
具體原型 2 folder.go
客戶端 main.go

實際示例:

在 golang 的上下文中,讓我們嘗試透過 os 檔案系統的示例來理解它。os 檔案系統有檔案和資料夾,資料夾本身也包含檔案和資料夾。每個檔案資料夾可以由inode介面表示。inode介面還有clone()函式。

inode.go

package main

type inode interface {
    print(string)
    clone() inode
}

檔案結構體表示為

file.go

package main

import "fmt"

type file struct {
	name string
}

func (f *file) print(indentation string) {
	fmt.Println(indentation + f.name)
}

func (f *file) clone() inode {
	return &file{name: f.name + "_clone"}
} 

資料夾結構體表示為

folder.go

package main

import "fmt"

type folder struct {
	childrens []inode
	name      string
}

func (f *folder) print(indentation string) {
	fmt.Println(indentation + f.name)
	for _, i := range f.childrens {
		i.print(indentation + indentation)
	}
}

func (f *folder) clone() inode {
	cloneFolder := &folder{name: f.name + "_clone"}
	var tempChildrens []inode
	for _, i := range f.childrens {
		copy := i.clone()
		tempChildrens = append(tempChildrens, copy)
	}
	cloneFolder.childrens = tempChildrens
	return cloneFolder
} 

由於檔案資料夾結構體都實現了列印克隆函式,因此它們屬於inode型別。此外,請注意檔案和資料夾中的克隆函式。它們的克隆函式返回各自檔案或資料夾的副本。在克隆時,我們為名稱欄位附加關鍵字“_clone”。讓我們編寫主函式來測試一下。

main.go

package main

import "fmt"

func main() {
    file1 := &file{name: "File1"}
    file2 := &file{name: "File2"}
    file3 := &file{name: "File3"}
    folder1 := &folder{
        childrens: []inode{file1},
        name:      "Folder1",
    }
    folder2 := &folder{
        childrens: []inode{folder1, file2, file3},
        name:      "Folder2",
    }
    fmt.Println("\nPrinting hierarchy for Folder2")
    folder2.print("  ")
    cloneFolder := folder2.clone()
    fmt.Println("\nPrinting hierarchy for clone Folder")
    cloneFolder.print("  ")
}

輸出:

Printing hierarchy for Folder2
  Folder2
    Folder1
        File1
    File2
    File3

Printing hierarchy for clone Folder
  Folder2_clone
    Folder1_clone
        File1_clone
    File2_clone
    File3_clone
  • 設計模式* go* golang* 原型*

Go(Golang)中的代理設計模式

來源:golangbyexample.com/proxy-design-pattern-in-golang/

注意:想了解其他所有設計模式如何在 GO 中實現嗎?請參見這個完整參考 – Go(Golang)中的所有設計模式

目錄

** 介紹:

  • UML 圖:

  • 對映

  • 實際示例:

  • 完整工作程式碼:

介紹:

代理設計模式是一種結構設計模式。此模式建議為對主物件的受控和智慧訪問提供額外的間接層。

在這個模式中,建立了一個新的代理類,它實現了與主物件相同的介面。這使你可以在主物件的實際邏輯之前執行某些行為。讓我們透過一個例子來更好地理解它。

  1. 一張簽帳金融卡是你銀行賬戶的代理。它遵循與銀行賬戶相同的介面,更容易使用。

  2. 像 Nginx 這樣的網路伺服器可以作為你的應用伺服器的代理。它提供

    • 對你的應用伺服器的受控訪問 – 例如,它可以進行速率限制。

    • 附加行為 – 例如,它可以進行某些快取。

讓我們看看 UML 圖。

UML 圖:

在下面的 UML 圖中

  • 主題:它表示代理和真實主題應遵循的介面。

  • 代理:代理類嵌入真實主題,並在完成處理後將請求傳遞給真實主題。

  • 真實主題:這是持有主業務邏輯的類,儲存在代理之後。

  • 客戶端: 可以與代理和真實主題進行互動,因為它們都遵循相同的介面。

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

下面是與上述 nginx 和應用伺服器的實際示例相對應的對映 UML 圖。

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

對映

下面的表格表示 UML 圖中的參與者與程式碼中的實際實現參與者之間的對映。

subject server.go
proxy nginx.go
realSubject application.go
client main.go

實際示例:

server.go

package main

type server interface {
    handleRequest(string, string) (int, string)
}

nginx.go

package main

type nginx struct {
    application       *application
    maxAllowedRequest int
    rateLimiter       map[string]int
}

func newNginxServer() *nginx {
    return &nginx{
        application:       &application{},
        maxAllowedRequest: 2,
        rateLimiter:       make(map[string]int),
    }
}

func (n *nginx) handleRequest(url, method string) (int, string) {
    allowed := n.checkRateLimiting(url)
    if !allowed {
        return 403, "Not Allowed"
    }
    return n.application.handleRequest(url, method)
}

func (n *nginx) checkRateLimiting(url string) bool {
    if n.rateLimiter[url] == 0 {
        n.rateLimiter[url] = 1
    }
    if n.rateLimiter[url] > n.maxAllowedRequest {
        return false
    }
    n.rateLimiter[url] = n.rateLimiter[url] + 1
    return true
}

application.go

package main

type application struct {
}

func (a *application) handleRequest(url, method string) (int, string) {
    if url == "/app/status" && method == "GET" {
        return 200, "Ok"
    }
    if url == "/create/user" && method == "POST" {
        return 201, "User Created"
    }
    return 404, "Not Ok"
}

main.go

package main

import "fmt"

func main() {
    nginxServer := newNginxServer()
    appStatusURL := "/app/status"
    createuserURL := "/create/user"
    httpCode, body := nginxServer.handleRequest(appStatusURL, "GET")
    fmt.Printf("\nUrl: %s\nHttpCode: %d\nBody: %s\n", appStatusURL, httpCode, body)
    httpCode, body = nginxServer.handleRequest(appStatusURL, "GET")
    fmt.Printf("\nUrl: %s\nHttpCode: %d\nBody: %s\n", appStatusURL, httpCode, body)
    httpCode, body = nginxServer.handleRequest(appStatusURL, "GET")
    fmt.Printf("\nUrl: %s\nHttpCode: %d\nBody: %s\n", appStatusURL, httpCode, body)
    httpCode, body = nginxServer.handleRequest(createuserURL, "POST")
    fmt.Printf("\nUrl: %s\nHttpCode: %d\nBody: %s\n", appStatusURL, httpCode, body)
    httpCode, body = nginxServer.handleRequest(createuserURL, "GET")
    fmt.Printf("\nUrl: %s\nHttpCode: %d\nBody: %s\n", appStatusURL, httpCode, body)
}

輸出:

Url: /app/status
HttpCode: 200
Body: Ok

Url: /app/status
HttpCode: 200
Body: Ok

Url: /app/status
HttpCode: 403
Body: Not Allowed

Url: /app/status
HttpCode: 201
Body: User Created

Url: /app/status
HttpCode: 404
Body: Not Ok

完整工作程式碼:

package main

import "fmt"

type server interface {
    handleRequest(string, string) (int, string)
}

type nginx struct {
    application       *application
    maxAllowedRequest int
    rateLimiter       map[string]int
}

func newNginxServer() *nginx {
    return &nginx{
        application:       &application{},
        maxAllowedRequest: 2,
        rateLimiter:       make(map[string]int),
    }
}

func (n *nginx) handleRequest(url, method string) (int, string) {
    allowed := n.checkRateLimiting(url)
    if !allowed {
        return 403, "Not Allowed"
    }
    return n.application.handleRequest(url, method)
}

func (n *nginx) checkRateLimiting(url string) bool {
    if n.rateLimiter[url] == 0 {
        n.rateLimiter[url] = 1
    }
    if n.rateLimiter[url] > n.maxAllowedRequest {
        return false
    }
    n.rateLimiter[url] = n.rateLimiter[url] + 1
    return true
}

type application struct {
}

func (a *application) handleRequest(url, method string) (int, string) {
    if url == "/app/status" && method == "GET" {
        return 200, "Ok"
    }
    if url == "/create/user" && method == "POST" {
        return 201, "User Created"
    }
    return 404, "Not Ok"
}

func main() {
    nginxServer := newNginxServer()
    appStatusURL := "/app/status"
    createuserURL := "/create/user"
    httpCode, body := nginxServer.handleRequest(appStatusURL, "GET")
    fmt.Printf("\nUrl: %s\nHttpCode: %d\nBody: %s\n", appStatusURL, httpCode, body)
    httpCode, body = nginxServer.handleRequest(appStatusURL, "GET")
    fmt.Printf("\nUrl: %s\nHttpCode: %d\nBody: %s\n", appStatusURL, httpCode, body)
    httpCode, body = nginxServer.handleRequest(appStatusURL, "GET")
    fmt.Printf("\nUrl: %s\nHttpCode: %d\nBody: %s\n", appStatusURL, httpCode, body)
    httpCode, body = nginxServer.handleRequest(createuserURL, "POST")
    fmt.Printf("\nUrl: %s\nHttpCode: %d\nBody: %s\n", appStatusURL, httpCode, body)
    httpCode, body = nginxServer.handleRequest(createuserURL, "GET")
    fmt.Printf("\nUrl: %s\nHttpCode: %d\nBody: %s\n", appStatusURL, httpCode, body)
}

輸出:

Url: /app/status
HttpCode: 200
Body: Ok

Url: /app/status
HttpCode: 200
Body: Ok

Url: /app/status
HttpCode: 403
Body: Not Allowed

Url: /app/status
HttpCode: 201
Body: User Created

Url: /app/status
HttpCode: 404
Body: Not Ok
  • 設計模式* go* golang* 代理設計模式*

Golang 中的佇列

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

目錄

** 介紹

  • 列表實現

  • 切片實現

介紹

可以使用 GO 中的

  1. container/list 包實現一個簡單的佇列

  2. 切片

佇列將有以下操作:

  1. 入隊

  2. 出隊

  3. 前端

  4. 大小

列表實現

package main

import (
    "container/list"
    "fmt"
)

type customQueue struct {
    queue *list.List
}

func (c *customQueue) Enqueue(value string) {
    c.queue.PushBack(value)
}

func (c *customQueue) Dequeue() error {
    if c.queue.Len() > 0 {
        ele := c.queue.Front()
        c.queue.Remove(ele)
    }
    return fmt.Errorf("Pop Error: Queue is empty")
}

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

func (c *customQueue) Size() int {
    return c.queue.Len()
}

func (c *customQueue) Empty() bool {
    return c.queue.Len() == 0
}

func main() {
    customQueue := &customQueue{
        queue: list.New(),
    }
    fmt.Printf("Enqueue: A\n")
    customQueue.Enqueue("A")
    fmt.Printf("Enqueue: B\n")
    customQueue.Enqueue("B")
    fmt.Printf("Size: %d\n", customQueue.Size())
    for customQueue.Size() > 0 {
        frontVal, _ := customQueue.Front()
        fmt.Printf("Front: %s\n", frontVal)
        fmt.Printf("Dequeue: %s\n", frontVal)
        customQueue.Dequeue()
    }
    fmt.Printf("Size: %d\n", customQueue.Size())
}

輸出:

Enqueue: A
Enqueue: B
Size: 2
Front: A
Dequeue: A
Front: B
Dequeue: B
Size: 0

切片實現

package main

import (
	"fmt"
	"sync"
)

type customQueue struct {
	queue []string
	lock  sync.RWMutex
}

func (c *customQueue) Enqueue(name string) {
	c.lock.Lock()
	defer c.lock.Unlock()
	c.queue = append(c.queue, name)
}

func (c *customQueue) Dequeue() error {
	if len(c.queue) > 0 {
		c.lock.Lock()
		defer c.lock.Unlock()
		c.queue = c.queue[1:]
		return nil
	}
	return fmt.Errorf("Pop Error: Queue is empty")
}

func (c *customQueue) Front() (string, error) {
	if len(c.queue) > 0 {
		c.lock.Lock()
		defer c.lock.Unlock()
		return c.queue[0], nil
	}
	return "", fmt.Errorf("Peep Error: Queue is empty")
}

func (c *customQueue) Size() int {
	return len(c.queue)
}

func (c *customQueue) Empty() bool {
	return len(c.queue) == 0
}

func main() {
	customQueue := &customQueue{
		queue: make([]string, 0),
	}

	fmt.Printf("Enqueue: A\n")
	customQueue.Enqueue("A")
	fmt.Printf("Enqueue: B\n")
	customQueue.Enqueue("B")
	fmt.Printf("Len: %d\n", customQueue.Size())

	for customQueue.Size() > 0 {
		frontVal, _ := customQueue.Front()
		fmt.Printf("Front: %s\n", frontVal)
		fmt.Printf("Dequeue: %s\n", frontVal)
		customQueue.Dequeue()
	}
	fmt.Printf("Len: %d\n", customQueue.Size())
} 

輸出:

Enqueue: A
Enqueue: B
Size: 2
Front: A
Dequeue: A
Front: B
Dequeue: B
Size: 0
```*


<!--yml

類別:未分類

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

-->

# Golang 中的範圍和二維陣列程式

> 來源:[`golangbyexample.com/range-sum-2d-array-go/`](https://golangbyexample.com/range-sum-2d-array-go/)

目錄

+   概述

+   程式

## **概述**

給定一個數字的二維矩陣。目標是計算矩陣中由**左上角**(row1, col1)和**右下角**(row2, col2)定義的矩形內元素的**和**。

看起來簡單,對吧。只需從左角迭代到右角並返回總和。但這裡有個問題。允許的時間複雜度是 O(1)

這裡是我們可以遵循的方法,以便能夠在 O(1)時間複雜度內返回答案

+   為該二維矩陣預計算另一個 sum_array

+   sum_array[i][j] = 從**左角**(0, 0)和**右角**(i, j)計算的數字之和。

+   對於給定的左角(row1, col1)和右角(row2, col2),計算

```go
topSum = sum_matrix[row1-1][col2]
leftSum = sum_matrix[row2][col1-1]
cornerSum = sum_matrix[row1-1][col1-1]
  • 然後返回
sum_matrix[row2][col2] - topSum - leftSum + cornerSum

程式

這裡是相同的程式。

package main

import "fmt"

type NumMatrix struct {
	matrix     [][]int
	sum_matrix [][]int
	numColumn  int
	numRows    int
}

func initNumArray(matrix [][]int) NumMatrix {
	numRows := len(matrix)
	numColumn := len(matrix[0])

	if numColumn == 0 || numRows == 0 {
		return NumMatrix{}
	}

	sum_matrix := make([][]int, numRows)

	for i := 0; i < numRows; i++ {
		sum_matrix[i] = make([]int, numColumn)
	}

	sum_matrix[0][0] = matrix[0][0]
	for i := 1; i < numRows; i++ {
		sum_matrix[i][0] = matrix[i][0] + sum_matrix[i-1][0]
	}

	for i := 1; i < numColumn; i++ {
		sum_matrix[0][i] = matrix[0][i] + sum_matrix[0][i-1]
	}

	for i := 1; i < numRows; i++ {
		for j := 1; j < numColumn; j++ {
			sum_matrix[i][j] = matrix[i][j] + sum_matrix[i-1][j] + sum_matrix[i][j-1] - sum_matrix[i-1][j-1]
		}
	}

	num_matrix := NumMatrix{
		matrix:     matrix,
		sum_matrix: sum_matrix,
		numColumn:  numColumn,
		numRows:    numRows,
	}
	return num_matrix
}

func (this *NumMatrix) SumRegion(row1 int, col1 int, row2 int, col2 int) int {

	topSum := 0
	leftSum := 0
	cornerSum := 0
	if row1 > 0 {
		topSum = this.sum_matrix[row1-1][col2]
	}

	if col1 > 0 {
		leftSum = this.sum_matrix[row2][col1-1]
	}

	if row1 > 0 && col1 > 0 {
		cornerSum = this.sum_matrix[row1-1][col1-1]
	}

	return this.sum_matrix[row2][col2] - topSum - leftSum + cornerSum
}

func main() {
	matrix := [][]int{{1, 3, 5}, {6, 7, 4}}
	na := initNumArray(matrix)

	output := na.SumRegion(0, 1, 1, 2)
	fmt.Println(output)

}

輸出

19

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

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

Go(Golang)中的範圍和陣列程式

來源:golangbyexample.com/range-sum-array-golang/

目錄

  • 概述

  • 程式

概述

有一個給定的數字陣列。目標是在該陣列中找到範圍和。這意味著將給定一個範圍,其中包含左索引和右索引。我們必須在給定的數字陣列中找到左索引和右索引之間的和。

看起來很簡單,對吧?只需從給定陣列的左索引迭代到右索引並返回和。但這裡有個陷阱。允許的時間複雜度是 O(1)

這裡是我們可以遵循的方法,以便能夠在 O(1)時間複雜度內返回答案

  • 從給定的數字陣列預計算另一個 sum_array

  • sum_array[i] = 從 0 索引到第 i 索引的數字之和。

  • 對於給定的左索引和右索引,只需返回 sum_array[left-1] – sum_array[right]。當然,我們需要驗證 left-1 是否大於或等於零。

程式

這是相同程式的實現。

package main

import "fmt"

type NumArray struct {
	sum_nums []int
}

func initNumArray(nums []int) NumArray {
	length := len(nums)
	sum_nums := make([]int, length)

	sum_nums[0] = nums[0]

	for i := 1; i < length; i++ {
		sum_nums[i] = nums[i] + sum_nums[i-1]
	}

	return NumArray{
		sum_nums: sum_nums,
	}
}

func (this *NumArray) SumRange(left int, right int) int {
	leftSum := 0
	if left > 0 {
		leftSum = this.sum_nums[left-1]
	}
	return this.sum_nums[right] - leftSum
}

func main() {
	nums := []int{1, 3, 5, 6, 2}
	na := initNumArray(nums)

	output := na.SumRange(2, 4)
	fmt.Println(output)

}

輸出

13

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

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

在 Go (Golang) 中將檔案讀入變數

來源:golangbyexample.com/read-file-variable-golang/

目錄

  • 概述

  • 使用 ioutil 包提供的 ReadFile 函式

  • 使用 os.Open 和 bytes.Buffer

  • 使用 os.Open 和 strings.Builder

概述

有多種方法可以在 golang 中將檔案讀入變數。以下是一些方法

  • 使用 ioutil 包提供的 ReadFile 函式

  • 使用 os.Open 然後使用 bytes.Buffer

  • 使用 os.Open 然後使用 strings.Builder

另外,請注意,只有在讀取小檔案時,將整個檔案讀入變數才有意義。如果檔案很大,那麼逐行讀取就更有意義。請參考這篇文章。

golangbyexample.com/read-large-file-line-by-line-go/

注意:在嘗試本教程中的示例之前,請在執行程式的目錄中建立一個名為 test.png 的檔案

使用 ioutil 包提供的 ReadFile 函式

golang.org/pkg/io/ioutil/#ReadFile

下面是相應的程式

package main

import (
    "fmt"
    "io/ioutil"
)

func main() {
    fileBytes, err := ioutil.ReadFile("test.png")
    if err != nil {
        panic(err)
    }
    fileString := string(fileBytes)
    fmt.Println(fileString)
}

輸出

Some Garbage Output depending upon the file

使用 os.Open 和 bytes.Buffer

golang.org/pkg/bytes/#Buffer

下面是相應的程式

package main

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

func main() {
	file, err := os.Open("test.png")
	if err != nil {
		log.Fatalf("Error while opening file. Err: %s", err)
	}
	defer file.Close()

	fileBuffer := new(bytes.Buffer)
	fileBuffer.ReadFrom(file)
	fileString := fileBuffer.String()

	fmt.Print(fileString)
}

輸出

Some Garbage Output depending upon the file

使用 os.Open 然後使用 strings.Builder

golang.org/pkg/strings/#Builder

下面是相應的程式

package main

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

func main() {
	file, err := os.Open("test.png")
	if err != nil {
		log.Fatalf("Error while opening file. Err: %s", err)
	}
	defer file.Close()

	fileBuffer := new(bytes.Buffer)
	fileBuffer.ReadFrom(file)
	fileString := fileBuffer.String()

	fmt.Print(fileString)
}

輸出

Some Garbage Output depending upon the file

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

相關文章