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

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

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

在 HTTP 響應中返回 401(未授權)狀態碼的 Go(Golang)實現。

來源:golangbyexample.com/401-http-status-response-go/

目錄

  • 概述

  • 程式

概述

net/http包提供狀態碼常量,可用於返回不同的狀態碼 - golang.org/src/net/http/status.go

同樣可以用於返回 401(未授權)HTTP 狀態碼。HTTP 401 狀態碼由以下常量定義。

http.StatusUnauthorized

在本文中,我們還將看到如何在返回 401(未授權)狀態碼的同時返回 JSON 主體。

程式

以下是相應的程式。

package main

import (
	"encoding/json"
	"log"
	"net/http"
)

func main() {
	handler := http.HandlerFunc(handleRequest)
	http.Handle("/example", handler)
	http.ListenAndServe(":8080", nil)
}

func handleRequest(w http.ResponseWriter, r *http.Request) {
	w.WriteHeader(http.StatusUnauthorized)
	w.Header().Set("Content-Type", "application/json")
	resp := make(map[string]string)
	resp["message"] = "Unauthorized"
	jsonResp, err := json.Marshal(resp)
	if err != nil {
		log.Fatalf("Error happened in JSON marshal. Err: %s", err)
	}
	w.Write(jsonResp)
	return
}

在這裡,我們使用WriteHeader函式來指定 401 HTTP 狀態碼,並使用Write函式來返回響應主體。上述程式碼將返回以下 JSON 請求主體作為響應。

{"message":"Unauthorized"}

執行上述程式。它將在本地機器的 8080 埠啟動一個伺服器。現在對伺服器進行以下 curl 呼叫。

curl -v -X POST http://localhost:8080/example

以下將是輸出。

* Connected to localhost (::1) port 8080 (#0)
> POST /example HTTP/1.1
> Host: localhost:8080
> User-Agent: curl/7.54.0
> Accept: */*
> 
< HTTP/1.1 401 Unauthorized
< Date: Sat, 10 Jul 2021 08:19:52 GMT
< Content-Length: 26
< Content-Type: text/plain; charset=utf-8
< 
* Connection #0 to host localhost left intact
{"message":"Unauthorized"}

如你所見,輸出將正確返回401狀態碼及其主體。

你也可以直接將 401 傳遞給 WriteHeader 函式以傳送 401 響應。

w.WriteHeader(401)

這也可以正常工作。試試看。

同時,檢視我們的 Golang 高階教程系列 - Golang 高階教程

  • 401* go* golang*

在 Go (Golang)中返回 403(禁止)狀態碼的 HTTP 響應

來源:golangbyexample.com/403-http-status-response-golang/

目錄

  • 概述

  • 程式

概述

net/http包提供了狀態碼常量,可以用於返回不同的狀態碼-

golang.org/src/net/http/status.go

同樣的方式也可以用來返回 403(禁止)HTTP 狀態碼。HTTP 403 狀態碼由以下常量定義。

http.StatusForbidden

在本文中,我們還將看到如何返回帶有 403(禁止)狀態碼的 JSON 主體。

程式

以下是相應的程式

package main

import (
	"encoding/json"
	"log"
	"net/http"
)

func main() {
	handler := http.HandlerFunc(handleRequest)
	http.Handle("/example", handler)
	http.ListenAndServe(":8080", nil)
}

func handleRequest(w http.ResponseWriter, r *http.Request) {
	w.WriteHeader(http.StatusForbidden)
	w.Header().Set("Content-Type", "application/json")
	resp := make(map[string]string)
	resp["message"] = "Forbidden"
	jsonResp, err := json.Marshal(resp)
	if err != nil {
		log.Fatalf("Error happened in JSON marshal. Err: %s", err)
	}
	w.Write(jsonResp)
	return
}

在這裡,我們使用WriteHeader函式來指定 403 HTTP 狀態碼,並使用Write函式返回響應體。上述程式碼將以下 JSON 請求體作為響應返回。

{"message":"Forbidden"}

執行上述程式。它將在你本地機器的 8080 埠啟動一個伺服器。現在進行以下 curl 呼叫到伺服器。

curl -v -X POST http://localhost:8080/example

下面將是輸出。

* Connected to localhost (::1) port 8080 (#0)
> POST /example HTTP/1.1
> Host: localhost:8080
> User-Agent: curl/7.54.0
> Accept: */*
> 
< HTTP/1.1 403 Forbidden
< Date: Sat, 10 Jul 2021 08:16:22 GMT
< Content-Length: 23
< Content-Type: text/plain; charset=utf-8
< 
* Connection #0 to host localhost left intact
{"message":"Forbidden"}

正如你從輸出中看到的,它將正確返回 403 狀態碼及其主體。

你也可以直接將 403 傳遞給 WriteHeader 函式以傳送 403 響應。

w.WriteHeader(403)

這同樣工作正常。試試看。

另外,檢視我們的 Golang 進階教程系列 - Golang 進階教程

  • 403* go* golang*

在 Go(Golang)中返回 404(資源未找到)HTTP 響應狀態碼。

來源:golangbyexample.com/404-http-status-code-golang/

目錄

  • 概述

  • 程式

概述

golang 的 HTTP 包提供了可以用於返回不同狀態碼的狀態碼常量 - golang.org/src/net/http/status.go

同樣也可以用於返回 404(資源未找到)HTTP 狀態碼。HTTP 404 狀態碼由下面的常量定義。

http.StatusNotFound

在本文中,我們還將看到如何在返回 404(資源未找到)HTTP 狀態碼時返回 JSON 正文。

程式

下面是相同的程式。

package main

import (
	"encoding/json"
	"log"
	"net/http"
)

func main() {
	handler := http.HandlerFunc(handleRequest)
	http.Handle("/example", handler)
	http.ListenAndServe(":8080", nil)
}

func handleRequest(w http.ResponseWriter, r *http.Request) {
	w.WriteHeader(http.StatusNotFound)
	w.Header().Set("Content-Type", "application/json")
	resp := make(map[string]string)
	resp["message"] = "Resource Not Found"
	jsonResp, err := json.Marshal(resp)
	if err != nil {
		log.Fatalf("Error happened in JSON marshal. Err: %s", err)
	}
	w.Write(jsonResp)
	return
}

在這裡,我們使用WriteHeader函式指定 404 HTTP 狀態碼,並使用Write函式返回響應正文。上述程式碼將下面的 JSON 請求正文返回作為響應。

{"message":"Resource Not Found"}

執行上述程式。它將在你的本地機器上啟動一個 8080 埠的伺服器。現在對伺服器進行如下 curl 呼叫。

curl -v -X POST http://localhost:8080/example

下面將是輸出。

* Connected to localhost (::1) port 8080 (#0)
> POST /example HTTP/1.1
> Host: localhost:8080
> User-Agent: curl/7.54.0
> Accept: */*
> 
< HTTP/1.1 404 Not Found
< Date: Sat, 10 Jul 2021 06:18:12 GMT
< Content-Length: 32
< Content-Type: text/plain; charset=utf-8
< 
* Connection #0 to host localhost left intact
{"message":"Resource Not Found"}

從輸出中可以看出,它正確地返回了404狀態碼及其正文。

你也可以直接將 404 傳遞給WriteHeader函式來傳送 404 響應。

w.WriteHeader(404)

這也能正常工作。試試看。

golang 的net/http包也提供了一個"NotFound"處理程式,可以用於每次返回特定 API 的 404。

golang.org/pkg/net/http/#NotFound

此處理程式函式返回 404 狀態及下面的響應正文。

404 page not found

下面是相同的簡單程式。

package main

import (
	"net/http"
)

func main() {
	http.HandleFunc("/example", http.NotFound)
	http.ListenAndServe(":8080", nil)
}

在上述程式中,我們簡單地為localhost:8080/example API 指定了 NotFound 處理程式,如下所示。

http.HandleFunc("/example", http.NotFound)

執行上述程式。它將在你的本地機器上啟動一個 8080 埠的伺服器。現在對伺服器進行如下 curl 呼叫。

curl -v -X POST http://localhost:8080/example
* Connected to localhost (::1) port 8080 (#0)
> POST /example HTTP/1.1
> Host: localhost:8080
> User-Agent: curl/7.54.0
> Accept: */*
> 
< HTTP/1.1 404 Not Found
< Content-Type: text/plain; charset=utf-8
< X-Content-Type-Options: nosniff
< Date: Sat, 10 Jul 2021 06:23:41 GMT
< Content-Length: 19
< 
404 page not found
* Connection #0 to host localhost left intact

此外,請檢視我們的 Golang 高階教程系列 - Golang 高階教程

  • 404* go* golang*

在 Go(Golang)中返回 500 狀態碼或內部伺服器錯誤的 HTTP 響應

來源:golangbyexample.com/500-status-http-response-golang/

目錄

  • 概述

  • 程式

概述

net/http包的 golang 提供了狀態碼常量,可用於返回不同的狀態碼 - golang.org/src/net/http/status.go

同樣也可以用來返回 500(StatusInternalServerError)HTTP 狀態碼。HTTP 500 狀態碼由以下常量定義。

http.StatusInternalServerError

在本文中,我們還將看到如何返回帶有 500(StatusInternalServerError)狀態碼的 JSON 體。

程式

以下是相同的程式。

package main

import (
	"encoding/json"
	"log"
	"net/http"
)

func main() {
	handler := http.HandlerFunc(handleRequest)
	http.Handle("/example", handler)
	http.ListenAndServe(":8080", nil)
}

func handleRequest(w http.ResponseWriter, r *http.Request) {
	w.WriteHeader(http.StatusInternalServerError)
	w.Header().Set("Content-Type", "application/json")
	resp := make(map[string]string)
	resp["message"] = "Some Error Occurred"
	jsonResp, err := json.Marshal(resp)
	if err != nil {
		log.Fatalf("Error happened in JSON marshal. Err: %s", err)
	}
	w.Write(jsonResp)
	return
}

在這裡,我們使用WriteHeader函式指定 500 的 http 狀態碼,並使用Write函式返回響應體。上述程式碼在響應中返回以下 JSON 請求體。

{"message":"Some Error Occurred"}

執行上述程式。這將在你的本地機器上啟動一個 8080 埠的伺服器。現在對伺服器進行以下 curl 呼叫。

curl -v -X POST http://localhost:8080/example

以下將是輸出

* Connected to localhost (::1) port 8080 (#0)
> POST /example HTTP/1.1
> Host: localhost:8080
> User-Agent: curl/7.54.0
> Accept: */*
> 
< HTTP/1.1 500 Internal Server Error
< Date: Sat, 10 Jul 2021 10:49:52 GMT
< Content-Length: 33
< Content-Type: text/plain; charset=utf-8
< 
* Connection #0 to host localhost left intact
{"message":"Some Error Occurred"}

從輸出中可以看到,它將正確返回 500 狀態碼以及響應體。

你也可以直接將 500 傳遞給 WriteHeader 函式以傳送 500 響應。

w.WriteHeader(500)

這也能正常工作。試試看。

另外,檢視我們的 Golang 進階教程系列 - Golang 進階教程

  • 500* go* golang*

在 Go (Golang) 中從函式返回一個函式

來源:golangbyexample.com/return-func-from-func-go/

在 Golang 中,函式是一級變數,這意味著

  • 它們可以被賦值給一個變數

  • 作為函式引數傳遞

  • 從函式返回

在從另一個函式返回一個函式時,必須在返回列表中指定函式的確切簽名。如下例所示

  • getAreaFunc 函式的返回型別是 func(int, int) int
func getAreaFunc() func(int, int)
  • getAreaFunc 函式因此可以返回型別為 func(int, int) int 的函式

程式碼:

package main

import "fmt"

func main() {
    areaF := getAreaFunc()
    res := areaF(2, 4)
    fmt.Println(res)
}

func getAreaFunc() func(int, int) int {
    return func(x, y int) int {
        return x * y
    }
}

輸出:

8

在 Go(Golang)中以 HTTP 響應返回影像或檔案。

來源:golangbyexample.com/image-http-response-golang/

目錄

概述

  • 示例

概述

ResponseWriter 介面的 Write 方法可以用於在 HTTP 響應體中傳送 imagefile。當我們將檔案或影像作為 HTTP 響應的一部分傳送時,Content-Type 響應頭為

application/octet-stream

在 Go 中,響應由 ResponseWriter 介面表示。這裡是介面的連結 –

https://golang.org/pkg/net/http/#ResponseWriter

ResponseWriter 介面由 HTTP 處理程式用於構造 HTTP 響應。它提供了三個函式來設定響應引數。

  • Header – 用於寫入響應頭。

  • Write([]byte) – 用於寫入響應體。

  • WriteHeader(statusCode int) – 用於寫入 HTTP 狀態碼。

Write 函式可用於設定響應體。它接受一個位元組切片作為輸入。因此,我們需要先將檔案或影像讀取到位元組切片中,然後再將其作為引數傳遞給 Write 函式。為此,我們將使用 ioutil 包提供的 ReadFile 函式。此外,還有一個 Header 函式。此函式可用於使用 Content-Type 頭設定響應體的內容型別。

w.Header().Set("Content-Type", "application/octet-stream")

此外,請注意 WriteHeader 函式可用於設定響應的 HTTP 狀態碼。

示例

讓我們看看如何將檔案或影像作為 HTTP 響應的一部分傳送的示例。下面是相應的程式。

package main

import (
	"io/ioutil"
	"net/http"
)

func main() {
	handler := http.HandlerFunc(handleRequest)
	http.Handle("/photo", handler)
	http.ListenAndServe(":8080", nil)
}

func handleRequest(w http.ResponseWriter, r *http.Request) {
	fileBytes, err := ioutil.ReadFile("test.png")
	if err != nil {
		panic(err)
	}
	w.WriteHeader(http.StatusOK)
	w.Header().Set("Content-Type", "application/octet-stream")
	w.Write(fileBytes)
	return
}

這就是我們如何在 Go 中將檔案或影像讀取到變數中的。

fileBytes, err := ioutil.ReadFile("test.png")

然後我們將這個變數傳遞給 Write 函式。

w.Write(fileBytes)

請注意,在上面的程式中,我們傳送的是本地機器上存在的 test.png。您可以將其替換為您機器上存在的任何其他檔案,可以是 png 或其他檔案。

此外,我們正在使用 WriteHeader 函式來指定 200 HTTP 狀態碼。我們還設定了正確的頭部。

w.Header().Set("Content-Type", "application/octet-stream")

執行上面的程式。它將在您本地機器的 8080 埠啟動一個伺服器。現在向伺服器發出下面的 curl 呼叫。請注意在 curl 呼叫中,我們還將輸出儲存到本地檔案。

curl -v -X POST http://localhost:8080/example > temp.png

輸出將類似於下面的內容。

* Connected to localhost (::1) port 8080 (#0)
> POST /example HTTP/1.1
> Host: localhost:8080
> User-Agent: curl/7.54.0
> Accept: */*
> 
< HTTP/1.1 200 OK
< Date: Sat, 10 Jul 2021 19:32:47 GMT
< Content-Type: image/png
< Transfer-Encoding: chunked
< 
{ [5846 bytes data]
100  5833    0  5833    0     0   957k      0 --:--:-- --:--:-- --:--:-- 1139k

現在檢查您從中發出 curl 呼叫的當前目錄。在該目錄下會有一個名為 test.png 的檔案,這就是伺服器傳送的相同檔案。

此外,請檢視我們的 Golang 高階教程系列 - Golang 高階教程

在 Go (Golang) 中返回退出狀態碼

來源:golangbyexample.com/return-exit-status-code-go/

目錄

  • 概述**

  • 程式碼

概述

golang 的 ‘os’ 包提供了一個 Exit 函式,可以用來以狀態碼退出當前程式。

  • 狀態碼零表示成功

  • 非零狀態碼錶示錯誤。

一旦呼叫此函式,程式會立即退出。即使是延遲函式也不會被呼叫。

還需注意狀態碼應在範圍 [0, 125] 內

func Exit(code int)

讓我們來看一個工作程式碼

程式碼

package main

import (
    "fmt"
    "os"
)

func main() {
    success := true
    if success {
        fmt.Println("Success")
        os.Exit(0)
    } else {
        fmt.Println("Failure")
        os.Exit(1)
    }
}

輸出

嘗試將成功設定為 false,以檢視不同的輸出

Success
$ echo $?
0
  • 程式碼* 退出* go* golang* 作業系統* 狀態*

在 Go(Golang)中返回 JSON 體作為 HTTP 響應

來源:golangbyexample.com/json-response-body-http-go/

目錄

  • 概述**

  • 示例

概述

net/http包中 ResponseWriter 介面的Write方法可用於在 HTTP 響應中設定 JSON 體

在 GO 中,響應由ResponseWriter介面表示。這裡是介面的連結 –

golang.org/pkg/net/http/#ResponseWriter

ResponseWriter 介面由 HTTP 處理程式用於構建 HTTP 響應。它提供三個函式來設定響應引數

  • 頭部 – 用於寫入響應頭

  • Write([]byte) – 用於寫入響應體

  • WriteHeader(statusCode int) – 用於寫入 HTTP 狀態碼

Write函式可以用於設定響應體。它接受一個位元組切片作為輸入。此外,還有一個Header函式。該函式可用於透過 Content-Type 頭設定響應體的內容型別。例如,在 JSON 響應體的情況下,我們需要將 Content-Type 頭設定為“application/json”。

w.Header().Set("Content-Type", "application/json")

另外,請注意WriteHeader函式可以用於設定響應的 HTTP 狀態碼

示例

讓我們來看一個傳送 HTTP 狀態碼和 JSON 響應體的示例

以下是相同的程式

package main

import (
	"encoding/json"
	"log"
	"net/http"
)

func main() {
	handler := http.HandlerFunc(handleRequest)
	http.Handle("/example", handler)
	http.ListenAndServe(":8080", nil)
}

func handleRequest(w http.ResponseWriter, r *http.Request) {
	w.WriteHeader(http.StatusCreated)
	w.Header().Set("Content-Type", "application/json")
	resp := make(map[string]string)
	resp["message"] = "Status Created"
	jsonResp, err := json.Marshal(resp)
	if err != nil {
		log.Fatalf("Error happened in JSON marshal. Err: %s", err)
	}
	w.Write(jsonResp)
	return
}

在上述程式中,這就是我們如何建立 JSON 響應。我們使用json.Marshal函式將map[string]string轉換為 JSON 位元組。

resp := make(map[string]string)
resp["message"] = "Status Created"
jsonResp, err := json.Marshal(resp)
if err != nil {
	log.Fatalf("Error happened in JSON marshal. Err: %s", err)
}
w.Write(jsonResp)

然後它使用Write函式返回 JSON 響應體。上述程式碼返回以下 JSON 響應體作為響應

{"message":"Status Created"}

此外,我們使用WriteHeader函式來指定 201 HTTP 狀態碼。

執行上述程式。它將在本地機器的 8080 埠啟動一個伺服器。現在請對伺服器進行以下 curl 呼叫

curl -v -X POST http://localhost:8080/example

以下將是輸出

* Connected to localhost (::1) port 8080 (#0)
> POST /example HTTP/1.1
> Host: localhost:8080
> User-Agent: curl/7.54.0
> Accept: */*
> 
< HTTP/1.1 201 Created
< Date: Sat, 10 Jul 2021 10:40:33 GMT
< Content-Length: 28
< Content-Type: text/plain; charset=utf-8
< 
* Connection #0 to host localhost left intact
{"message":"Status Created"}

從輸出中可以看到,它將正確返回201狀態碼以及 JSON 體。

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

在 Go(Golang)中返回純文字體的 HTTP 響應。

來源:golangbyexample.com/plain-text-response-body-golang/

目錄

  • 概述

  • 示例

概述

Write方法的 ResponseWriter 介面在net/http包中可用於在 HTTP 響應中設定text/plain體。

在 GO 中,響應由ResponseWriter介面表示。介面的連結在這裡 – golang.org/pkg/net/http/#ResponseWriter

ResponseWriter 介面由 HTTP 處理程式用於構造 HTTP 響應。它提供三個函式來設定響應引數。

  • Header – 用於寫入響應頭。

  • Write([]byte) – 用於寫入響應體。

  • WriteHeader(statusCode int) – 用於寫入 HTTP 狀態碼。

Write函式可用於設定響應體。它接受一個位元組切片作為輸入。此外,還有一個Header函式。此函式可用於透過 Content-Type 頭設定響應體的內容型別。例如,對於 text/plain 響應體,我們需要將 Content-Type 頭設定為“text/plain”。

w.Header().Set("Content-Type", "text/plain")

此外,請注意WriteHeader函式可用於設定響應的 HTTP 狀態碼。

示例

讓我們看看傳送 HTTP 狀態碼和text/plain響應體的示例。

下面是相應的程式。

package main

import (
	"net/http"
)

func main() {
	handler := http.HandlerFunc(handleRequest)
	http.Handle("/example", handler)
	http.ListenAndServe(":8080", nil)
}

func handleRequest(w http.ResponseWriter, r *http.Request) {
	w.WriteHeader(http.StatusOK)
	w.Header().Set("Content-Type", "application/text")
	w.Write([]byte("Success"))
	return
}

我們使用Write函式返回 text/plain 響應體。上述程式碼返回以下text/plain體作為響應。

Success

此外,我們正在使用WriteHeader函式來指定200的 HTTP 狀態碼。我們還設定了正確的頭資訊。

執行上述程式。它將在本地機器的 8080 埠啟動一個伺服器。現在對伺服器進行以下 curl 呼叫。

curl -v -X POST http://localhost:8080/example

下面將是輸出。

* Connected to localhost (::1) port 8080 (#0)
> POST /example HTTP/1.1
> Host: localhost:8080
> User-Agent: curl/7.54.0
> Accept: */*
> 
< HTTP/1.1 200 OK
< Date: Sat, 10 Jul 2021 19:01:56 GMT
< Content-Length: 7
< Content-Type: text/plain; charset=utf-8
< 
* Connection #0 to host localhost left intact
Success

從輸出中可以看到,它將正確返回200狀態碼以及text/plain體。此外,Content-Type響應頭被設定為text/plain

此外,請檢視我們的 Golang 進階教程系列 - Golang 進階教程

當恐慌在 Go(Golang)中被恢復時,函式的返回值

來源:golangbyexample.com/return-value-function-panic-recover-go/

目錄

  • 概述

  • 程式

概述

當恐慌被恢復時,恐慌函式的返回值將是該函式返回型別的預設值。

程式

讓我們來看一個程式示例

package main
import (
    "fmt"
)
func main() {
    a := []int{5, 6}
    val, err := checkAndGet(a, 2)
    fmt.Printf("Val: %d\n", val)
    fmt.Println("Error: ", err)
}
func checkAndGet(a []int, index int) (int, error) {
    defer handleOutOfBounds()
    if index > (len(a) - 1) {
        panic("Out of bound access for slice")
    }
    return a[index], nil
}
func handleOutOfBounds() {
    if r := recover(); r != nil {
        fmt.Println("Recovering from panic:", r)
    }
}

輸出

Recovering from panic: Out of bound access for slice
Val: 0
Error: 

在上面的程式中,我們有一個checkAndGet函式,它獲取 int 切片中特定索引的值。如果傳遞給此函式的索引大於(切片長度-1),則會引發恐慌。同時還有一個handleOutOfBounds函式用於從恐慌中恢復。因此,我們將索引 2 傳遞給checkAndGet函式,它引發了恐慌,並在handleOutOfBounds函式中得以恢復。這就是我們首先得到這個輸出的原因。

Recovering from panic: Out of bound access for slice

請注意在主函式中,我們以這樣的方式重新獲取checkAndGet的返回值。

val, err := checkAndGet(a, 2)

checkAndGet有兩個返回值

  • int

  • error

由於checkAndGet會引發恐慌,而該恐慌在 handleOutOfBounds 函式中被恢復,因此checkAndGet的返回值將是其型別的預設值。

因此

fmt.Printf("Val: %d\n", val)

輸出

Val: 0

因為零是int型別的預設值。

而且

fmt.Println("Error: ", err)

輸出

Error: 

因為 nil 是error型別的預設值。

如果你不想返回型別的預設零值,那麼可以使用命名返回值。我們來看一個程式示例。

package main
import (
    "fmt"
)
func main() {
    a := []int{5, 6}
    val, err := checkAndGet(a, 2)
    fmt.Printf("Val: %d\n", val)
    fmt.Println("Error: ", err)
}
func checkAndGet(a []int, index int) (value int, err error) {
    value = 10
    defer handleOutOfBounds()
    if index > (len(a) - 1) {
        panic("Out of bound access for slice")
    }
    value = a[index]
    return value, nil
}
func handleOutOfBounds() {
    if r := recover(); r != nil {
        fmt.Println("Recovering from panic:", r)
    }
}

輸出

Recovering from panic: Out of bound access for slice
Val: 10
Error: 

這個程式與前面的程式相同,唯一的區別是我們在checkAndGet函式中使用了命名返回值。

func checkAndGet(a []int, index int) (value int, err error)

我們在checkAndGet函式中將命名返回值設定為 10

value = 10

這就是為什麼我們在這個程式中得到以下輸出,因為引發了恐慌並得以恢復

Recovering from panic: Out of bound access for slice
Val: 10
Error: 

還要注意,如果程式中沒有引發恐慌,那麼它將輸出正確的索引值。

在 Go (Golang) 中從函式返回多個值

來源:golangbyexample.com/go-return-multiples-values-function/

目錄

  • 概述

  • 函式的簽名

  • 返回值

    • 程式碼:
  • 命名返回值

    • 程式碼:

概述

函式是一組執行特定任務的語句。

函式的簽名

func func_name(input_parameters) return_values{
  //body
}

在 Golang 中,一個函式可以返回多個值。下面是一個函式的示例。

  • 名稱為 “f”

  • 接受兩個整型引數

  • 返回一個整型的單個值

func f(a int, b int) int {
  return a + b 
}

返回值

  • 如上所述,一個函式可以有一個或多個返回值。假設有一個函式 sum_avg 返回兩個值:總和和平均值。注意,當返回多個值時,返回值型別必須用括號括起來。多個返回值的示例。
func sum_avg(a, b int) (int, int)
  • 根據約定,錯誤作為函式的最後一個引數返回。示例
func sum(a, b int) (int, error)
  • 在呼叫函式中收集多個返回值。在下面的示例中
result, err := sum(2, 3) 

程式碼:

package main

import "fmt"

func main() {
    sum, avg := sum_avg(4, 2)
    fmt.Println(sum)
    fmt.Println(avg)
}

func sum_avg(a, b int) (int, int) {
    sum := a + b
    avg := (a + b) / 2
    return sum, avg
}

輸出

6
3

命名返回值

Go 函式可以具有命名返回值。使用命名返回值時,返回值在函式中不需要初始化。命名變數在簽名中指定。沒有命名值時,只指定返回型別。也可以為某些返回值命名。對於其他返回值,只能指定型別。

  • 見下面的示例:result 是命名返回值。
func sum(a, b int) (result int)
  • 多個命名返回值
func sum_avg(a, b int) (sum int, avg int)
  • 使用命名返回值時,相同型別的連續值只需指定一次型別。
func sum_avg(a, b int) (sum, avg int)
  • 命名返回值被初始化為該型別的零值。因此我們不需要在函式中重新初始化它。在下面的示例中,sumavg 沒有使用 := 符號再次初始化。

程式碼:

package main

import "fmt"

func main() {
    sum, avg := sum_avg(4, 2)
    fmt.Println(sum)
    fmt.Println(avg)
}

func sum_avg(a, b int) (sum, avg int) {
    sum = a + b
    avg = (a + b) / 2
    return
} 

輸出

6
3
```*


<!--yml

類別: 未分類

日期: 2024-10-13 06:42:59

-->

# 在 Go (Golang)中反轉連結串列

> 來源:[`golangbyexample.com/reverse-linked-list-golang/`](https://golangbyexample.com/reverse-linked-list-golang/)

目錄

+   概述

+   程式

## **概述**

目標是反轉給定的連結串列。

示例

```go
Input:  3->2->1
Output: 1->2->3

程式

以下是相應的程式

package main

import "fmt"

func main() {
	first := initList()
	first.AddFront(1)
	first.AddFront(2)
	first.AddFront(3)
	first.AddFront(4)

	first.Head.Traverse()
	first.Reverse()
        fmt.Println("")
	first.Head.Traverse()

}

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

type ListNode struct {
	Val  int
	Next *ListNode
}

func (l *ListNode) Traverse() {
	for l != nil {
		fmt.Println(l.Val)
		l = l.Next
	}
}

type SingleList struct {
	Len  int
	Head *ListNode
}

func (s *SingleList) Reverse() {

	curr := s.Head
	var prev *ListNode
	var next *ListNode

	for curr != nil {
		next = curr.Next
		curr.Next = prev
		prev = curr
		curr = next
	}
	s.Head = prev
}
func (s *SingleList) AddFront(num int) {
	ele := &ListNode{
		Val: num,
	}
	if s.Head == nil {
		s.Head = ele
	} else {
		ele.Next = s.Head
		s.Head = ele
	}
	s.Len++
}

輸出

4
3
2
1

1
2
3
4

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

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

在 Go 語言中反轉一個數字或整數

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

目錄

  • 概述

  • 程式

概述

目標是反轉一個整數。整數可以是負數。以下是一些示例

Input: 123
Output: 321

Input: 140
Output: 41

Input: -123
Output: -321

Input: 0
Output: 0

這裡是策略

  • 首先,將輸入數字變為正數

  • 使用下面的邏輯遍歷數字,每次獲取最後一位數字。使用最後一位數字來建立reversedDigit

for x > 0 {
	lastDigit := x % 10
	reversedDigit = reversedDigit*10 + lastDigit

	x = x / 10
}

這裡是完整的程式。

程式

package main

import (
	"fmt"
	"math"
)

func main() {
	reversedInteger := reverse(123)
	fmt.Println(reversedInteger)

	reversedInteger = reverse(140)
	fmt.Println(reversedInteger)

	reversedInteger = reverse(-123)
	fmt.Println(reversedInteger)

	reversedInteger = reverse(0)
	fmt.Println(reversedInteger)
}

func reverse(x int) int {
	sign := "positive"
	if x >= 0 {
		sign = "positive"
	} else {
		sign = "negative"
	}

	x = int(math.Abs(float64(x)))

	var reversedDigit int

	for x > 0 {
		lastDigit := x % 10
		reversedDigit = reversedDigit*10 + lastDigit

		x = x / 10
	}

	if sign == "negative" {
		reversedDigit = reversedDigit * -1
	}
	return reversedDigit
}

輸出

321
41
-321
0

在 Go (Golang)中反轉字串

來源:golangbyexample.com/reverse-a-string-in-golang/

在 Golang 中,字串是一個位元組序列。字串字面量實際上表示的是一個 UTF-8 位元組序列。在 UTF-8 中,ASCII 字元是單位元組的,對應於前 128 個 Unicode 字元。所有其他字元的位元組數在 1 到 4 位元組之間。因此,無法在字串中索引一個字元。在 GO 中,rune資料型別表示一個 Unicode 點。一旦字串被轉換為rune陣列,就可以在該陣列中索引字元。你可以在這裡瞭解更多關於rune的內容 – golangbyexample.com/understanding-rune-in-golang

因此,在下面的程式中為了反轉一個字串,我們首先將字串轉換為rune陣列,以便可以索引該陣列以獲取單個字元。一旦我們獲得了單個字元,就可以從末尾開始不斷新增到一個新字串中。

package main

import "fmt"

func main() {
    sample := "ab£d"
    r := []rune(sample)
    var res []rune
    for i := len(r) - 1; i >= 0; i-- {
        res = append(res, r[i])
    }
    fmt.Printf("Result: %s\n", string(res))
}

輸出:

Result: d£ba

在 Go 中反轉雙向連結串列 (Golang)

來源:golangbyexample.com/reverse-doubly-linked-list-golang/

目錄

  • 概述

  • 程式

概述

雙向連結串列可以透過以下兩種方法反轉:

  • 透過交換節點的前後指標。

  • 透過使用棧

在本教程中,我們將介紹第一種方法,即透過交換前後指標。

假設我們有以下雙向連結串列

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

反轉後,雙向連結串列將如下所示:

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

程式

在這種方法中,我們需要注意以下幾點:

  • 交換雙向連結串列的頭和尾

  • 交換所有節點的前後指標

package main
import "fmt"
type node struct {
    data string
    prev *node
    next *node
}
type doublyLinkedList struct {
    len  int
    tail *node
    head *node
}
func initDoublyList() *doublyLinkedList {
    return &doublyLinkedList{}
}
func (d *doublyLinkedList) AddFrontNodeDLL(data string) {
    newNode := &node{
        data: data,
    }
    if d.head == nil {
        d.head = newNode
        d.tail = newNode
    } else {
        newNode.next = d.head
        d.head.prev = newNode
        d.head = newNode
    }
    d.len++
}
func (d *doublyLinkedList) AddEndNodeDLL(data string) {
    newNode := &node{
        data: data,
    }
    if d.head == nil {
        d.head = newNode
        d.tail = newNode
    } else {
        currentNode := d.head
        for currentNode.next != nil {
            currentNode = currentNode.next
        }
        newNode.prev = currentNode
        currentNode.next = newNode
        d.tail = newNode
    }
    d.len++
}
func (d *doublyLinkedList) TraverseForward() error {
    if d.head == nil {
        return fmt.Errorf("TraverseError: List is empty")
    }
    temp := d.head
    for temp != nil {
        fmt.Printf("value = %v, prev = %v, next = %v\n", temp.data, temp.prev, temp.next)
        temp = temp.next
    }
    fmt.Println()
    return nil
}
func (d *doublyLinkedList) Size() int {
    return d.len
}
func (d *doublyLinkedList) ReverseDLL() {
    currentNode := d.head
    var nextInList *node
    d.head, d.tail = d.tail, d.head
    for currentNode != nil {
        nextInList = currentNode.next
        currentNode.next, currentNode.prev = currentNode.prev, currentNode.next
        currentNode = nextInList
    }
}
func main() {
    doublyList := initDoublyList()
    fmt.Printf("Add Front Node: C\n")
    doublyList.AddFrontNodeDLL("C")
    fmt.Printf("Add Front Node: B\n")
    doublyList.AddFrontNodeDLL("B")
    fmt.Printf("Add Front Node: A\n")
    doublyList.AddFrontNodeDLL("A")
    fmt.Printf("Add End Node: D\n")
    doublyList.AddEndNodeDLL("D")
    fmt.Printf("Add End Node: E\n")
    doublyList.AddEndNodeDLL("E")
    fmt.Printf("Size of doubly linked ist: %d\n", doublyList.Size())
    err := doublyList.TraverseForward()
    if err != nil {
        fmt.Println(err.Error())
    }
    fmt.Println("Reversing Doubly Linked List")
    doublyList.ReverseDLL()
    fmt.Printf("Size of doubly linked ist: %d\n", doublyList.Size())
    err = doublyList.TraverseForward()
    if err != nil {
        fmt.Println(err.Error())
    }
}

輸出

Add Front Node: C
Add Front Node: B
Add Front Node: A
Add End Node: D
Add End Node: E
Size of doubly linked ist: 5
value = A, prev = <nil>, next = &{B 0xc000070060 0xc000070020}
value = B, prev = &{A <nil>0xc000070040}, next = &{C 0xc000070040 0xc000070080}
value = C, prev = &{B 0xc000070060 0xc000070020}, next = &{D 0xc000070020 0xc0000700a0}
value = D, prev = &{C 0xc000070040 0xc000070080}, next = &{E 0xc000070080 <nil>}
value = E, prev = &{D 0xc000070020 0xc0000700a0}, next = <nil>Reversing Doubly Linked List
Size of doubly linked ist: 5
value = E, prev = <nil>, next = &{D 0xc0000700a0 0xc000070020}
value = D, prev = &{E <nil>0xc000070080}, next = &{C 0xc000070080 0xc000070040}
value = C, prev = &{D 0xc0000700a0 0xc000070020}, next = &{B 0xc000070020 0xc000070060}
value = B, prev = &{C 0xc000070080 0xc000070040}, next = &{A 0xc000070040 <nil>}
value = A, prev = &{B 0xc000070020 0xc000070060}, next =</nil></nil></nil></nil></nil></nil></nil> 

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

在 Go 語言中,針對給定連結串列按 k 組反轉節點

來源:golangbyexample.com/reverse-nodes-k-group-linked-list-golang/

目錄

  • 概述

  • 程式

概述

給定一個連結串列和一個數字 k,按 k 組反轉連結串列中的節點。

例如

Input: 1->2->3->4->5->6->7
k: 3
Output: 3->2->1->6->5->4->7

如果連結串列最後一組的長度小於 k,則保留最後一組不變

程式

package main

import "fmt"

func main() {
	first := initList()
	first.AddFront(4)
	first.AddFront(3)
	first.AddFront(2)
	first.AddFront(1)

	first.Head.Traverse()
	temp := ReverseKGroup(first.Head, 3)
        fmt.Println()
	temp.Traverse()

}

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

type ListNode struct {
	Val  int
	Next *ListNode
}

func (l *ListNode) Traverse() {
	for l != nil {
		fmt.Println(l.Val)
		l = l.Next
	}
}

type SingleList struct {
	Len  int
	Head *ListNode
}

func ReverseKGroup(head *ListNode, k int) *ListNode {

	curr := head
	var prev *ListNode
	var next *ListNode

	i := 0

	for curr != nil && i < k {
		i++
		curr = curr.Next
	}
	if i == k {
		curr = head
	} else {
		return head
	}

	i = 0
	for curr != nil && i < k {
		next = curr.Next
		curr.Next = prev
		prev = curr
		curr = next
		i++
	}

	head.Next = ReverseKGroup(curr, k)
	return prev
}

func (s *SingleList) AddFront(num int) {
	ele := &ListNode{
		Val: num,
	}
	if s.Head == nil {
		s.Head = ele
	} else {
		ele.Next = s.Head
		s.Head = ele
	}
	s.Len++
}

輸出

1
2
3
4

3
2
1
4

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

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

在 Go (Golang)中反轉字串的母音

來源:golangbyexample.com/reverse-vowels-string-golang/

目錄

  • 概述

  • 程式

概述

給定一個字串。目標是反轉該字串中的所有母音。

示例 1

Input: "simple"
Output: "sempli"

示例 2

Input: "complex"
Output: "cemplox"

程式

以下是相應的程式

package main

import "fmt"

func reverseVowels(s string) string {
	runeS := []rune(s)
	lenS := len(runeS)

	for i, j := 0, lenS-1; i < j; {
		for i < j {
			if !vowel(runeS[i]) {
				i++
			} else {
				break
			}
		}
		if i == j {
			break
		}
		for i < j {
			if !vowel(runeS[j]) {
				j--
			} else {
				break
			}
		}

		if i == j {
			break
		}

		runeS[i], runeS[j] = runeS[j], runeS[i]
		i++
		j--

	}

	return string(runeS)

}

func vowel(s rune) bool {
	if s == 'a' || s == 'e' || s == 'i' || s == 'o' || s == 'u' {
		return true
	}

	if s == 'A' || s == 'E' || s == 'I' || s == 'O' || s == 'U' {
		return true
	}

	return false
}

func main() {
	output := reverseVowels("simple")
	fmt.Println(output)

	output = reverseVowels("complex")
	fmt.Println(output)

}

輸出:

sempli
cemplox

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

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

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

在 Go 中反轉句子中的單詞 (Golang)

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

目錄

  • 概述

  • 程式

概述

目標是反轉給定句子中的單詞

示例

Input: "hello world"
Output: "word hello"

另一個例子。如果輸入包含一個單詞,則返回該單詞。

Input: "hello"
Output: "hello"

這是策略

  • 首先,我們反轉整個字串。因此,對於“hello world”來說,它變成了
"dlrow olleh"
  • 然後我們反轉每個單詞
"world hello"
  • 我們還需要處理開頭或結尾的多餘空格。

程式

這是相應的程式。

package main

import (
	"fmt"
	"regexp"
	"strings"
)

func reverseWords(s string) string {

	runeArray := []rune(s)
	length := len(runeArray)

	reverseRuneArray := reverse(runeArray)

	for i := 0; i < length; {
		for i < length && string(reverseRuneArray[i]) == " " {
			i++
		}
		if i == length {
			break
		}
		wordStart := i

		for i < length && string(reverseRuneArray[i]) != " " {
			i++
		}

		wordEnd := i - 1

		reverseRuneArray = reverseIndex(reverseRuneArray, wordStart, wordEnd)

	}

	noSpaceString := strings.TrimSpace(string(reverseRuneArray))
	space := regexp.MustCompile(`\s+`)
	return space.ReplaceAllString(noSpaceString, " ")
}

func reverse(s []rune) []rune {
	length := len(s)
	start := 0
	end := length - 1
	for start < end {
		s[start], s[end] = s[end], s[start]
		start++
		end--
	}
	return s
}

func reverseIndex(s []rune, i, j int) []rune {

	start := i
	end := j
	for start < end {
		s[start], s[end] = s[end], s[start]
		start++
		end--
	}
	return s
}

func main() {
	output := reverseWords("hello world")
	fmt.Println(output)

	output = reverseWords("hello")
	fmt.Println(output)
}

輸出

world hello
hello

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

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

在 Go(Golang)中旋轉連結串列

來源:golangbyexample.com/rotate-linked-list-golang/

目錄

  • 概述

  • 程式

概述

目標是將給定列表按指定數量向右旋轉。

示例

Input: 1->2->3->4->5
k: 2

Output: 4->5->1->2->3

程式

這是相應的程式。

package main

import "fmt"

func main() {
	first := initList()
	first.AddFront(5)
	first.AddFront(4)
	first.AddFront(3)
	first.AddFront(2)
	first.AddFront(1)

	first.Head.Traverse()

	head := rotateRight(first.Head, 2)
	fmt.Println("")
	head.Traverse()
	fmt.Println("")

}

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

type ListNode struct {
	Val  int
	Next *ListNode
}

func (l *ListNode) Traverse() {
	for l != nil {
		fmt.Print(l.Val)
		l = l.Next
	}
}

type SingleList struct {
	Len  int
	Head *ListNode
}

func (s *SingleList) Reverse() {

	curr := s.Head
	var prev *ListNode
	var next *ListNode

	for curr != nil {
		next = curr.Next
		curr.Next = prev
		prev = curr
		curr = next
	}
	s.Head = prev
}
func (s *SingleList) AddFront(num int) {
	ele := &ListNode{
		Val: num,
	}
	if s.Head == nil {
		s.Head = ele
	} else {
		ele.Next = s.Head
		s.Head = ele
	}
	s.Len++
}

func rotateRight(head *ListNode, k int) *ListNode {

	if head == nil {
		return nil
	}

	if k == 0 {
		return head
	}

	lenList := 0

	curr := head
	var last *ListNode

	for curr != nil {
		lenList++
		last = curr
		curr = curr.Next
	}

	k = k % lenList
	if k == 0 {
		return head
	}

	curr = head

	newHeadIndex := lenList - k

	var prev *ListNode

	for i := 0; i < newHeadIndex; i++ {
		prev = curr
		curr = curr.Next
	}

	newHeadNode := prev.Next

	prev.Next = nil

	last.Next = head
	return newHeadNode
}

輸出

12345
45123

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

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

在 Go (Golang)中順時針旋轉對稱矩陣或影像

來源:golangbyexample.com/rotate-image-clockwise-golang/

概述

給定一個以矩陣形式表示的影像,將該矩陣或影像順時針旋轉。

例如

輸入:

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

輸出:

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

思路是逐一遍歷所有邊界,並就地交換每一側。上述矩陣的外邊界是

7 4  1
8     2 
9 6 3

我們可以這樣就地旋轉矩陣

7->1->3->9
4->2->6->8

一個 n*n 大小的對稱矩陣將有n-1個邊界。例如,上述矩陣有兩個邊界

第一個邊界

7 4 1
8    2 
9 6 3

第二個邊界

5

目錄

** 程式

程式

下面是相應的程式

package main

import "fmt"

func main() {
	matrix := [][]int{{1, 2, 3}, {4, 5, 6}, {7, 8, 9}}
	rotate(matrix)

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

func rotate(matrix [][]int) {

	matrixSize := len(matrix)

	startRow := 0
	endRow := matrixSize - 1
	startColumn := 0
	endColumn := matrixSize - 1
	for i := 0; i < matrixSize; i++ {
		totalCycles := endRow - startRow

		for j := 0; j < totalCycles; j++ {
			temp := matrix[startRow][startColumn+j]
			matrix[startRow][startColumn+j] = matrix[endRow-j][startColumn]

			matrix[endRow-j][startColumn] = matrix[endRow][endColumn-j]

			matrix[endRow][endColumn-j] = matrix[startRow+j][endColumn]

			matrix[startRow+j][endColumn] = temp
		}

		startRow = startRow + 1
		endRow = endRow - 1
		startColumn = startColumn + 1
		endColumn = endColumn - 1
	}

	fmt.Println(matrix)

}

輸出

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

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

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

Go 語言中的腐爛橙子程式(Golang)

來源:golangbyexample.com/rotting-oranges-program-go/

目錄

  • 概述

  • 程式

概述

給定一個 m*n 矩陣,其中每個條目包含三個值

  • 0 – 表示該條目為空

  • 1 – 表示該條目包含新鮮橙子

  • 2 – 表示該條目包含腐爛的橙子

腐爛的橙子將在 1 天內腐爛相鄰的橙子。對於給定的橙子,位於上、下、左和右的任何橙子都是相鄰橙子。對角線的橙子不算在內。

目標是找出所有橙子腐爛的天數。如果所有橙子無法腐爛,則寫-1。這種情況發生在新鮮橙子無法從腐爛橙子到達時。

示例 1

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

頂部有一個腐爛的橙子。它將腐爛相鄰的兩個橙子。這些腐爛的橙子將進一步腐爛它們相鄰的橙子。

示例 2

Input: [[1,1]]
Output: -1

程式

下面是相應的程式

package main

import "fmt"

func orangesRotting(grid [][]int) int {
	numRows := len(grid)
	numColumns := len(grid[0])

	queue := make([][2]int, 0)

	for i := 0; i < numRows; i++ {
		for j := 0; j < numColumns; j++ {
			if grid[i][j] == 2 {
				queue = append(queue, [2]int{i, j})
			}
		}
	}

	neighboursIndex := [][2]int{{1, 0}, {-1, 0}, {0, 1}, {0, -1}}
	numMinutes := 0
	for {
		n := len(queue)
		for i := 0; i < n; i++ {
			pop := queue[0]
			queue = queue[1:]

			a := pop[0]
			b := pop[1]
			for k := 0; k < 4; k++ {
				neighbourX := a + neighboursIndex[k][0]
				neighbourY := b + neighboursIndex[k][1]

				if isValid(neighbourX, neighbourY, numRows, numColumns) {
					if grid[neighbourX][neighbourY] == 1 {
						grid[neighbourX][neighbourY] = 2
						queue = append(queue, [2]int{neighbourX, neighbourY})
					}
				}

			}
		}

		if len(queue) == 0 {
			break
		}
		numMinutes++
	}

	for i := 0; i < numRows; i++ {
		for j := 0; j < numColumns; j++ {
			if grid[i][j] == 1 {
				return -1
			}
		}
	}

	return numMinutes
}

func isValid(i, j, numRows, numColumns int) bool {
	if i >= numRows || i < 0 {
		return false
	}

	if j >= numColumns || j < 0 {
		return false
	}
	return true
}

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

	output = orangesRotting([][]int{{1, 1}})
	fmt.Println(output)
}

輸出:

4
-1

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

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

同時,檢視我們的系統設計教程系列 - 系統設計教程系列

相關文章