在 HTTP 响应中返回 401(未授权)状态码的 Go(Golang)实现。
目录
-
概述
-
程序
概述
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 高级教程
在 Go (Golang)中返回 403(禁止)状态码的 HTTP 响应
目录
-
概述
-
程序
概述
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 进阶教程
在 Go(Golang)中返回 404(资源未找到)HTTP 响应状态码。
目录
-
概述
-
程序
概述
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 高级教程
在 Go(Golang)中返回 500 状态码或内部服务器错误的 HTTP 响应
目录
-
概述
-
程序
概述
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 进阶教程
在 Go (Golang) 中从函数返回一个函数
在 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 响应返回图像或文件。
目录
概述
- 示例
概述
ResponseWriter 接口的 Write 方法可以用于在 HTTP 响应体中发送 image 或 file。当我们将文件或图像作为 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) 中返回退出状态码
目录
-
概述**
-
代码
概述
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)中返回 JSON 体作为 HTTP 响应
目录
-
概述**
-
示例
概述
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 响应。
目录
-
概述
-
示例
概述
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) 中从函数返回多个值
目录
-
概述
-
函数的签名
-
返回值
- 代码:
-
命名返回值
- 代码:
概述
函数是一组执行特定任务的语句。
函数的签名
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)
- 命名返回值被初始化为该类型的零值。因此我们不需要在函数中重新初始化它。在下面的示例中,sum 和 avg 没有使用 := 符号再次初始化。
代码:
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 语言中反转一个数字或整数
目录
-
概述
-
程序
概述
目标是反转一个整数。整数可以是负数。以下是一些示例
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)中反转字符串
在 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)
目录
-
概述
-
程序
概述
双向链表可以通过以下两种方法反转:
-
通过交换节点的前后指针。
-
通过使用栈
在本教程中,我们将介绍第一种方法,即通过交换前后指针。
假设我们有以下双向链表
反转后,双向链表将如下所示:
程序
在这种方法中,我们需要注意以下几点:
-
交换双向链表的头和尾
-
交换所有节点的前后指针
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)中反转字符串的元音
目录
-
概述
-
程序
概述
给定一个字符串。目标是反转该字符串中的所有元音。
示例 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)
目录
-
概述
-
程序
概述
目标是反转给定句子中的单词
示例
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)中旋转链表
目录
-
概述
-
程序
概述
目标是将给定列表按指定数量向右旋转。
示例
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)中顺时针旋转对称矩阵或图像
概述
给定一个以矩阵形式表示的图像,将该矩阵或图像顺时针旋转。
例如
输入:
[[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)
目录
-
概述
-
程序
概述
给定一个 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
同时,查看我们的系统设计教程系列 - 系统设计教程系列