通过示例学习-Go-语言-2023-八-
通过示例学习 Go 语言 2023(八)
Go (Golang) 中的 Cookies
目录
** 什么是 cookie
-
在 golang 中设置 cookie
-
在发起请求时设置 cookie。
-
在响应传入请求时设置 cookie
-
-
在 golang 中读取 cookie
什么是 cookie
Cookies 是一种在客户端存储信息的方式。客户端可以是浏览器、移动应用程序或任何发起 HTTP 请求的事物。Cookies 基本上是存储在浏览器缓存内存中的一些文件。当您浏览任何支持 cookies 的网站时,会在 cookie 中记录与您活动相关的某种信息。这些信息可以是任何内容。简而言之,cookies 存储用户活动的历史信息。这些信息存储在客户端的计算机上。由于 cookie 存储在文件中,因此即使用户关闭浏览器窗口或重启计算机,这些信息也不会丢失。cookie 还可以存储登录信息。实际上,诸如令牌等登录信息通常仅存储在 cookies 中。cookies 是按域存储的。属于特定域的本地存储 cookies 在每个请求中发送到该域。它们在每个请求中作为头的一部分发送。因此,cookie 本质上只是一种头。
您可以在这里阅读关于 HTTP cookie 的一般信息 – en.wikipedia.org/wiki/HTTP_cookie
Cookies 可以发送
-
作为 HTTP 客户端的 Cookie 头
-
作为 HTTP 服务器响应中的 Set-cookie 头
golang 中的 cookie 如下所示
golang.org/src/net/http/cookie.go
type Cookie struct {
Name string
Value string
Path string // optional
Domain string // optional
Expires time.Time // optional
RawExpires string // for reading cookies only
// MaxAge=0 means no 'Max-Age' attribute specified.
// MaxAge<0 means delete cookie now, equivalently 'Max-Age: 0'
// MaxAge>0 means Max-Age attribute present and given in seconds
MaxAge int
Secure bool
HttpOnly bool
SameSite SameSite
Raw string
Unparsed []string // Raw text of unparsed attribute-value pairs
}
详细信息请参见 tools.ietf.org/html/rfc6265
中上述 cookie 的每个字段。
让我们详细了解与 cookies 相关的两个方面
-
在 golang 中设置 cookie
-
读取 cookie
在 golang 中设置 cookie
我们已经提到 cookie 只是一个头。因此,要设置特定的 cookie,我们只需设置该头。
有两种情况
-
在发起请求时设置 cookie。
-
在响应传入请求时设置 cookie
让我们详细了解每一个
在发起请求时设置 cookie。
这是 golang 作为 HTTP 客户端的情况。AddCookie 方法可用于添加 cookie。如果我们对两个不同的名称和值调用此方法,那么这两个名称和值都将添加到结果 cookie 中
package main
import (
"fmt"
"log"
"net/http"
"net/http/cookiejar"
)
var client http.Client
func init() {
jar, err := cookiejar.New(nil)
if err != nil {
log.Fatalf("Got error while creating cookie jar %s", err.Error())
}
client = http.Client{
Jar: jar,
}
}
func main() {
cookie := &http.Cookie{
Name: "token",
Value: "some_token",
MaxAge: 300,
}
cookie2 := &http.Cookie{
Name: "clicked",
Value: "true",
MaxAge: 300,
}
req, err := http.NewRequest("GET", "http://google.com", nil)
if err != nil {
log.Fatalf("Got error %s", err.Error())
}
req.AddCookie(cookie)
req.AddCookie(cookie2)
for _, c := range req.Cookies() {
fmt.Println(c)
}
resp, err := client.Do(req)
if err != nil {
log.Fatalf("Error occured. Error is: %s", err.Error())
}
defer resp.Body.Close()
fmt.Printf("StatusCode: %d\n", resp.StatusCode)
}
输出
token=some_token
clicked=true
StatusCode: 200
在上述程序中,HTTP 客户端添加了两个 cookies。这两个 cookies 将在调用 google.com 时发送。
golang 中的 HTTP 客户端还允许您指定一个 CookieJar,该 jar 管理在进行外部 HTTP 请求时存储和发送 cookies。顾名思义,可以把它看作一个装有 cookies 的 jar。
HTTP 客户端以两种方式使用此 jar。
-
在此 Jar 中添加 cookies。您可以显式地将 cookies 添加到此 jar。如果服务器在响应头中发送 Set-Cookies 头,cookies 也将被添加到 jar 中。所有在 Set-Cookie 头中指定的 cookies 将被添加。
-
在进行任何外部 HTTP 请求时咨询此 jar。它检查此 jar 以了解特定域需要发送哪些 cookies。
有关 golang 中 CookieJar 的更多信息,可以参考此链接 golangbyexample.com/cookiejar-golang/
。
在响应传入请求时设置 cookie。
这是 golang 作为 HTTP 服务器的情况。http.ResponseWriter 结构提供了一个方便的方法来设置 cookie。下面是该方法的签名。
func SetCookie(w ResponseWriter, cookie *Cookie)
此方法用于在 ResponseWriter 上设置 cookies。它向响应头添加一个 Set-Cookie 头。此 Set-Cookie 头用于发送在客户端或浏览器端设置的 cookie。然后,当客户端向服务器发出后续调用时,该 cookie 将被发送回服务器。
以下是相应的程序。
package main
import (
"net/http"
)
func main() {
docHandler := http.HandlerFunc(docHandler)
http.Handle("/doc", docHandler)
http.ListenAndServe(":8080", nil)
}
func docHandler(w http.ResponseWriter, r *http.Request) {
cookie := &http.Cookie{
Name: "id",
Value: "abcd",
MaxAge: 300,
}
http.SetCookie(w, cookie)
w.WriteHeader(200)
w.Write([]byte("Doc Get Successful"))
return
}
使用以下命令运行上述程序。
go run main.go
服务器将在 8080 端口启动。
现在从浏览器发起 API 调用 localhost:8080/doc。服务器在响应中发送了以下 Set-Cookie。
Set-Cookie: id=abcd; Max-Age=300
这在 API 调用的响应头中也可见。见下图。
有关 Set-Cookie 头的更多详细信息,请参阅此 link。该链接包含了解 Set-Cookie 头在 golang 中的所有细节。
在 golang 中读取 cookie。
net/http Request 结构提供了一个方便的方法来读取特定名称的 cookie。下面是该方法的签名。golang.org/pkg/net/http/#Request.Cookie
func (r *Request) Cookie(name string) (*Cookie, error)
要打印所有 cookies,我们可以遍历 http.Request 结构的 Cookies 方法。我们可以为此使用 range 关键字。
for _, c := range r.Cookies() {
fmt.Println(c)
}
以下是相应的程序,演示 http.Request 结构的 Cookie 和 Cookies 方法。
package main
import (
"fmt"
"log"
"net/http"
)
func main() {
docHandler := http.HandlerFunc(docHandler)
http.Handle("/doc", docHandler)
http.ListenAndServe(":8080", nil)
}
func docHandler(w http.ResponseWriter, r *http.Request) {
fmt.Println("Cookies in API Call:")
tokenCookie, err := r.Cookie("token")
if err != nil {
log.Fatalf("Error occured while reading cookie")
}
fmt.Println("\nPrinting cookie with name as token")
fmt.Println(tokenCookie)
fmt.Println("\nPrinting all cookies")
for _, c := range r.Cookies() {
fmt.Println(c)
}
fmt.Println()
w.WriteHeader(200)
w.Write([]byte("Doc Get Successful"))
return
}
运行上述程序并进行以下 curl 调用。
curl -X GET localhost:8080/doc --cookie "id=abcd; token=some_token"
curl 调用传递了两个 cookie 名称-值对。
-
id=abcd。
-
token=some_token。
它将产生以下输出。
Cookies in API Call:
Printing cookie with name as token
token=some_token
Printing all cookies
id=abcd
token=some_token
这就是我们如何打印给定名称 “token” 的特定 cookie。
tokenCookie, err := r.Cookie("token")
它的输出如所示。
token=some_token
这就是我们如何打印所有 cookies。
for _, c := range r.Cookies() {
fmt.Println(c)
}
它输出我们在 curl 调用中发送的 cookie 名称-值对。
id=abcd
token=some_token
这就是关于 golang 中的 cookie 的所有内容。希望你喜欢这个教程。请在评论中分享反馈。
另外,查看我们的 Golang 高级教程系列 – Golang 高级教程
在 Go 语言中复制数组或切片
目录
-
概述
-
复制一个数组
-
复制一个切片
概述
在 Go 语言中,数组是值类型,而切片是引用类型。因此,数组或切片如何复制到另一个数组或切片的方式是不同的。
复制一个数组
如上所述,数组在 Go 语言中是值类型。因此,数组变量名不是指向第一个元素的指针,而是表示整个数组。当
-
一个数组变量被赋值给另一个数组变量。
-
一个数组变量作为参数传递给一个函数。
我们用一个例子来说明上述要点
package main
import "fmt"
func main() {
sample1 := [2]string{"a", "b"}
fmt.Printf("Sample1 Before: %v\n", sample1)
sample2 := sample1
sample2[1] = "c"
fmt.Printf("Sample1 After assignment: %v\n", sample1)
fmt.Printf("Sample2: %v\n", sample2)
test(sample1)
fmt.Printf("Sample1 After Test Function Call: %v\n", sample1)
}
func test(sample [2]string) {
sample[0] = "d"
fmt.Printf("Sample in Test function: %v\n", sample)
}
输出
Sample1 Before: [a b]
Sample1 After assignment: [a b]
Sample2: [a c]
Sample in Test function: [d b]
Sample1 After Test Function Call: [a b]
在上述例子中,
-
我们将sample1赋值给sample2,然后在sample2的 0 索引处改变为不同的值。之后,当我们打印sample1时,发现它没有改变。这是因为当我们将sample1赋值给sample2时,会创建一个副本,改变sample2不会影响sample1。
-
我们将sample1传递给测试函数,然后在测试函数的 0 索引处再次改变其值。之后,当我们打印sample1时,发现它没有改变。原因相同,当sample1作为参数传递给测试函数时,会创建sample1的一个副本。
复制一个切片
Go 的builtin包提供了一个copy函数,可以用来复制切片。下面是这个函数的签名。它返回复制的元素数量。
func copy(dst, src []Type) int
在使用 copy 函数时,有两种情况需要考虑:
-
如果src的长度大于dst的长度,则复制的元素数量为dst的长度
-
如果dst的长度大于src的长度,则复制的元素数量为src的长度
基本上,复制的元素数量是(src, dst)长度的最小值。
还要注意,一旦复制完成,dst中的任何更改将不会反映在src中,反之亦然。
package main
import "fmt"
func main() {
src := []int{1, 2, 3, 4, 5}
dst := make([]int, 5)
numberOfElementsCopied := copy(dst, src)
fmt.Printf("Number Of Elements Copied: %d\n", numberOfElementsCopied)
fmt.Printf("dst: %v\n", dst)
fmt.Printf("src: %v\n", src)
//After changing numbers2
dst[0] = 10
fmt.Println("\nAfter changing dst")
fmt.Printf("dst: %v\n", dst)
fmt.Printf("src: %v\n", src)
}
输出
Number Of Elements Copied: 5
dst: [1 2 3 4 5]
src: [1 2 3 4 5]
After changing dst
dst: [10 2 3 4 5]
src: [1 2 3 4 5]
```*
<!--yml
类别:未分类
日期:2024-10-13 06:18:40
-->
# Go 中的复制函数(Golang)
> 来源:[`golangbyexample.com/copy-function-in-golang/`](https://golangbyexample.com/copy-function-in-golang/)
Go 的 **builtin** 包提供了 **copy** 函数,可以用于复制切片。以下是此函数的签名。它接收两个切片 **dst** 和 **src**,并将数据从 **src** 复制到 **dst**。它返回复制的元素数量。
```go
func copy(dst, src []Type) int
根据签名,复制函数可以用于从 src 复制不同类型的切片到 dst。在使用复制函数时,有两种情况需要考虑:
-
如果 src 的长度大于 dst 的长度,则复制的元素数量为 dst 的长度。
-
如果 dst 的长度大于 src 的长度,则复制的元素数量为 src 的长度。
基本上,复制的元素数量为 (src, dst) 长度的最小值。
还要注意,一旦复制完成,dst 中的任何更改将不会反映在 src 中,反之亦然,除非 src 和 dst 引用同一个切片。
一个简单的整数类型复制示例,说明上述要点。
package main
import "fmt"
func main() {
src := []int{1, 2, 3, 4, 5}
dst := make([]int, 5)
numberOfElementsCopied := copy(dst, src)
fmt.Printf("Number Of Elements Copied: %d\n", numberOfElementsCopied)
fmt.Printf("dst: %v\n", dst)
fmt.Printf("src: %v\n", src)
//After changing dst
dst[0] = 10
fmt.Println("\nAfter changing dst")
fmt.Printf("dst: %v\n", dst)
fmt.Printf("src: %v\n", src)
//Length of destination is less than length of source
dst = make([]int, 4)
numberOfElementsCopied = copy(dst, src)
fmt.Println("\nLength of dst less than src")
fmt.Printf("Number Of Elements Copied: %d\n", numberOfElementsCopied)
fmt.Printf("dst: %v\n", dst)
fmt.Printf("src: %v\n", src)
//Length of destination is greater than length of source
dst = make([]int, 6)
numberOfElementsCopied = copy(dst, src)
fmt.Println("\nLength of dst less than src")
fmt.Printf("Number Of Elements Copied: %d\n", numberOfElementsCopied)
fmt.Printf("dst: %v\n", dst)
fmt.Printf("src: %v\n", src)
}
输出
Number Of Elements Copied: 5
dst: [1 2 3 4 5]
src: [1 2 3 4 5]
After changing dst
dst: [10 2 3 4 5]
src: [1 2 3 4 5]
Length of dst less than src
Number Of Elements Copied: 4
dst: [1 2 3 4]
src: [1 2 3 4 5]
Length of dst less than src
Number Of Elements Copied: 5
dst: [1 2 3 4 5 0]
src: [1 2 3 4 5]
字符串的复制函数
在 Go 中,字符串只是一系列字节。因此,将字符串复制到字节切片是合法的。
package main
import "fmt"
func main() {
src := "abc"
dst := make([]byte, 3)
numberOfElementsCopied := copy(dst, src)
fmt.Printf("Number Of Elements Copied: %d\n", numberOfElementsCopied)
fmt.Printf("dst: %v\n", dst)
fmt.Printf("src: %v\n", src)\
}
输出
Number Of Elements Copied: 3
dst: [97 98 99]
src: abc
在使用复制函数时,源和目标也可以重叠。因此,可以从一个切片复制到自身。以下示例中,我们将切片的最后两个元素复制到同一顺序的前两个元素中。
package main
import "fmt"
func main() {
src := []int{1, 2, 3, 4, 5}
numberOfElementsCopied := copy(src, src[3:])
fmt.Printf("Number Of Elements Copied: %d\n", numberOfElementsCopied)
fmt.Printf("src: %v\n", src)
}
输出
Number Of Elements Copied: 2
src: [4 5 3 4 5]
结论
这就是 Go 中的复制函数。希望你喜欢这篇文章。
在 Go(Golang)中计算字符串中子字符串的实例
目录
-
概述**
-
代码:
概述
在 GO 中,字符串采用 UTF-8 编码。GO 的strings包提供了一个Count方法,可以用来获取特定字符串中非重叠子字符串的数量。
以下是该函数的签名
func Count(s, substr string) int
另外请注意,如果传递给函数的substr是一个空字符串,则返回值将为 1 加上给定字符串中的 Unicode 字符点数。
让我们看一下工作代码
代码:
package main
import (
"fmt"
"strings"
)
func main() {
//Case 1 Input string contains the substring
res := strings.Count("abcdabcd", "ab")
fmt.Println(res)
//Case 1 Input string doesn't contains the substring
res = strings.Count("abcdabcd", "xy")
fmt.Println(res)
//Case 1 Substring supplied is an empty string
res = strings.Count("abcdabcd", "")
fmt.Println(res)
}
输出:
2
0
9
```*
<!--yml
类别:未分类
日期:2024-10-13 06:47:48
-->
# 计算数字序列可能解码为字母的方式(Golang)
> 来源:[`golangbyexample.com/count-possible-decodings-digit-golang/`](https://golangbyexample.com/count-possible-decodings-digit-golang/)
目录
+ 概述
+ 程序
## **概述**
假设我们有以下数字到字母的映射
```go
'A' -> "1"
'B' -> "2"
...
'Z' -> "26"
目标是计算给定数字序列的可能解码数量
示例
Input: '15'
Output: 2
15 can be decoded as "AE" or "O"
程序
这里是相应的程序。
package main
import (
"fmt"
"strconv"
)
func numDecodings(s string) int {
runeArray := []rune(s)
length := len(runeArray)
if length == 0 {
return 0
}
if string(runeArray[0]) == "0" {
return 0
}
numwaysArray := make([]int, length)
numwaysArray[0] = 1
if length == 1 {
return numwaysArray[0]
}
secondDigit := string(runeArray[0:2])
num, _ := strconv.Atoi(secondDigit)
if num > 10 && num <= 19 {
numwaysArray[1] = 2
} else if num > 20 && num <= 26 {
numwaysArray[1] = 2
} else if num == 10 || num == 20 {
numwaysArray[1] = 1
} else if num%10 == 0 {
numwaysArray[1] = 0
} else {
numwaysArray[1] = 1
}
for i := 2; i < length; i++ {
firstDigit := string(runeArray[i])
if firstDigit != "0" {
numwaysArray[i] = numwaysArray[i] + numwaysArray[i-1]
}
secondDigit := string(runeArray[i-1 : i+1])
fmt.Println(i)
fmt.Println(secondDigit)
num, _ := strconv.Atoi(secondDigit)
if num >= 10 && num <= 26 {
numwaysArray[i] = numwaysArray[i] + numwaysArray[i-2]
}
}
return numwaysArray[length-1]
}
func main() {
output := numDecodings("15")
fmt.Println(output)
}
输出
2
注意: 请查看我们的 Golang 高级教程。本系列教程详尽,并且我们努力涵盖所有概念及实例。本教程适合那些希望获得专业知识和扎实理解 Golang 的人 - Golang 高级教程
如果你有兴趣了解如何在 Golang 中实现所有设计模式,那么这篇文章适合你 - 所有设计模式 Golang
在 Go (Golang) 中计数无防守单元格的程序
目录
-
概述
-
程序
概述
给定两个整数 m 和 n,表示一个 m*n 网格。除此之外,还给定两个 2D 整数数组
-
守卫的位置为 guards[i] = [rowi , columni]。它表示第 i 个守卫的位置
-
墙壁的位置为 guards[j] = [rowi , columni]。它表示第 i 个墙壁的位置
守卫可以向所有方向看
-
北
-
南
-
东
-
西
除非被墙壁阻挡。守卫能看到的所有单元格都算作已防守。目标是找出无防守单元格的数量
这里是相同的 leetcode 链接 – https://leetcode.com/problems/count-unguarded-cells-in-the-grid/
程序
以下是相同的程序
package main
import "fmt"
func countUnguarded(m int, n int, guards [][]int, walls [][]int) int {
occupancy := make([][]int, m)
for i := 0; i < m; i++ {
occupancy[i] = make([]int, n)
}
for _, val := range guards {
i := val[0]
j := val[1]
occupancy[i][j] = 2
}
for _, val := range walls {
i := val[0]
j := val[1]
occupancy[i][j] = -1
}
for i := 0; i < m; i++ {
for j := 0; j < n; j++ {
if occupancy[i][j] == 2 {
countUtil(i, j, m, n, &occupancy)
}
}
}
count := 0
for i := 0; i < m; i++ {
for j := 0; j < n; j++ {
if occupancy[i][j] == 0 {
count += 1
}
}
}
return count
}
func countUtil(x, y, m, n int, occupancy *([][]int)) {
for i := x + 1; i < m; i++ {
if (*occupancy)[i][y] == 0 {
(*occupancy)[i][y] = 1
}
if (*occupancy)[i][y] == -1 || (*occupancy)[i][y] == 2 {
break
}
}
for i := x - 1; i >= 0; i-- {
if (*occupancy)[i][y] == 0 {
(*occupancy)[i][y] = 1
}
if (*occupancy)[i][y] == -1 || (*occupancy)[i][y] == 2 {
break
}
}
for i := y + 1; i < n; i++ {
if (*occupancy)[x][i] == 0 {
(*occupancy)[x][i] = 1
}
if (*occupancy)[x][i] == -1 || (*occupancy)[x][i] == 2 {
break
}
}
for i := y - 1; i >= 0; i-- {
if (*occupancy)[x][i] == 0 {
(*occupancy)[x][i] = 1
}
if (*occupancy)[x][i] == -1 || (*occupancy)[x][i] == 2 {
break
}
}
}
func main() {
output := countUnguarded(4, 6, [][]int{{0, 0}, {1, 1}, {2, 3}}, [][]int{{0, 1}, {2, 2}, {1, 4}})
fmt.Println(output)
output = countUnguarded(3, 3, [][]int{{1, 1}}, [][]int{{0, 1}, {1, 0}, {2, 1}, {1, 2}})
fmt.Println(output)
}
输出
7
4
注意:查看我们的 Golang 高级教程。本系列教程内容详尽,我们尝试覆盖所有概念并附有示例。本教程适合那些希望获得专业知识和对 golang 有深入理解的人 – Golang 高级教程
如果你有兴趣了解所有设计模式在 Golang 中如何实现。如果是,那么这篇文章适合你 – 所有设计模式 Golang
此外,查看我们的系统设计教程系列 – 系统设计教程系列
在 Go (Golang)中计算无向图中无法到达的节点对
目录
-
概述
-
程序
概述
给定一个整数 n。有 n 个节点编号为 0 到 n-1。还有一个二维整数数组edges,其中edges[i] = [ai, bi]表示从 ai 到 bi 有一个无向节点。
目标是找到彼此无法到达的节点对数量
示例 1
n=3
edges=[{0,1}]
图
输出
2
我们有两个未连接的节点
[{0,2}, {1,2}]
示例 2
n=9
edges=[{0,1},{0,4},{0,5},{2,3},{2,6},{7,8}]
图
输出:
26
我们有 26 对未连接的节点
[{0,2}, {0,3}, {0,6}, {0,7}, {0,8},
{1,2}, {1,3}, {1,6}, {1,7}, {1,8},
{4,2}, {4,3}, {4,6}, {4,7}, {4,8},
{5,2}, {5,3}, {5,6}, {5,7}, {5,8},
{7,2}, {7,3}, {7,6},
{8,2}, {8,3}, {8,6}]
思路是从每个未访问的节点开始进行深度优先搜索,以识别每个连接图中的节点数。在上面的例子中,每个连接图中的节点数是
4
3
2
然后我们简单地找到每个连接图中的节点对数量
程序
以下是相应的程序
package main
import "fmt"
func countPairs(n int, edges [][]int) int64 {
nodeMap := make(map[int][]int)
for i := 0; i < len(edges); i++ {
nodeMap[edges[i][0]] = append(nodeMap[edges[i][0]], edges[i][1])
nodeMap[edges[i][1]] = append(nodeMap[edges[i][1]], edges[i][0])
}
visited := make(map[int]bool)
var output int64
var totalNodesVisited int64
for i := 0; i < n; i++ {
if !visited[i] {
nodeVisited := visit(i, nodeMap, &visited)
if totalNodesVisited != 0 {
output += totalNodesVisited * nodeVisited
}
totalNodesVisited += nodeVisited
}
}
return output
}
func visit(source_node int, nodeMap map[int][]int, visited *map[int]bool) int64 {
(*visited)[source_node] = true
var totalNodeVisited int64
totalNodeVisited = 1
neighbours, ok := nodeMap[source_node]
if ok {
for _, neighbour := range neighbours {
if !(*visited)[neighbour] {
nodeVisited := visit(neighbour, nodeMap, visited)
totalNodeVisited += nodeVisited
}
}
}
return totalNodeVisited
}
func main() {
n := 3
edges := [][]int{{0, 1}}
output := countPairs(n, edges)
fmt.Println(output)
n = 9
edges = [][]int{{0, 1}, {0, 4}, {0, 5}, {2, 3}, {2, 6}, {7, 8}}
output = countPairs(n, edges)
fmt.Println(output)
}
输出:
2
26
注意: 请查看我们的 Golang 高级教程。本系列教程内容详尽,努力覆盖所有概念及示例。此教程适合希望获得 Golang 专业知识和扎实理解的人 - Golang 高级教程
如果你有兴趣了解如何在 Golang 中实现所有设计模式,那么这篇文章适合你 - 所有设计模式 Golang
此外,请查看我们的系统设计教程系列 - 系统设计教程系列
在 Go (Golang) 中创建目录或文件夹
目录
-
概述
-
代码
概述
os.Mkdir() 函数可以用于在 Go 中创建目录或文件夹。
以下是该函数的签名。
func Mkdir(name string, perm FileMode)
它接受两个参数。
-
第一个参数是命名目录。如果命名目录是一个完全合格的路径,它将在该路径下创建一个目录。如果不是,它将相对于当前工作目录创建一个目录。
-
第二个参数指定权限位。文件夹或目录是使用此权限位创建的。
代码
package main
import (
"log"
"os"
)
func main() {
//Create a folder/directory at a full qualified path
err := os.Mkdir("/Users/temp", 0755)
if err != nil {
log.Fatal(err)
}
//Create a folder/directory at a full qualified path
err = os.Mkdir("temp", 0755)
if err != nil {
log.Fatal(err)
}
}
输出
It will create a directory temp at location /Users location and at the current working directory location
在 Go (Golang) 中创建一个新时间实例
在 Go 中,time.Time 结构用于表示时间或日期的实例。下面是创建新时间实例的三种方法
目录
** 使用 time.Now()")
-
使用 time.Date()")
-
使用 time.Parse()")
使用 time.Now()
time.Now() 函数可用于获取当前本地时间戳。该函数的签名是
func Now() Time
使用 time.Date()
time.Date() 函数接受年份、月份、日期、小时、分钟、秒、纳秒和位置,并返回一个时间格式为 yyyy-mm-dd hh:mm:ss + nsec,具有与给定位置相对应的适当时区。该函数的签名是
func Date(year int, month Month, day, hour, min, sec, nsec int, loc *Location) Time
使用 time.Parse()
time.Parse() 可用于将时间的字符串表示转换为 time.Time 实例。该函数的签名是
func Parse(layout, value string) (Time, error)
time.Parse 函数接受两个参数 –
-
第一个参数是包含时间格式占位符的布局
-
第二个参数是表示时间的实际格式化字符串。
下面是一个演示上述三种方法的工作代码示例
package main
import (
"fmt"
"time"
)
func main() {
//time.Now() example
t := time.Now()
fmt.Println(t)
//time.Date() Example
t = time.Date(2021, time.Month(2), 21, 1, 10, 30, 0, time.UTC)
fmt.Println(t)
//time.Parse() Example
//Parse YYYY-MM-DD
t, _ = time.Parse("2006-01-02", "2020-01-29")
fmt.Println(t)
}
输出:
2020-02-03 11:34:10.85639 +0530 IST m=+0.000297951
2021-02-21 01:10:30 +0000 UTC
2020-01-29 00:00:00 +0000 UTC
在 Go(Golang)中创建一个空文件。
目录
-
概述
-
代码:
概述
os.Create() 可用于在 Go 中创建一个空文件。该函数的签名为
func Create(name string) (*File, error)
基本上这个函数
-
创建一个模式为 0666 的命名文件。
-
如果文件已经存在,它将截断该文件。
-
如果路径有问题,它将返回一个路径错误。
-
它返回一个文件描述符,可用于读取和写入。
代码:
package main
import (
"log"
"os"
)
func main() {
file, err := os.Create("emptyFile.txt")
if err != nil {
log.Fatal(err)
}
defer file.Close()
}
输出:
Check the contents of the file. It will be empty
在 Go (Golang)中创建字符串的重复副本
来源:
golangbyexample.com/create-count-repeating-copies-string-golang/
目录
-
概述**
-
代码:
概述
GO 的strings包提供了一个Repeat方法,可用于创建给定字符串的重复副本。它的输入为重复次数。
以下是函数的签名。它返回字符串的副本。
func Repeat(s string, count int) string
让我们看看有效的代码
代码:
package main
import (
"fmt"
"strings"
)
func main() {
res := strings.Repeat("abc", 4)
fmt.Println(res)
}
输出:
abcabcabcabc
在 Go(Golang)中创建/初始化/声明 map
目录
-
概述
-
声明一个 Map
-
创建一个 Map
-
使用 Make
概述
map 是 Golang 内置的数据类型,类似于哈希表,它将键映射到值。
下面是 map 的格式:
map[key_type]value_type
key_type和value_type可以是不同类型或相同类型。在下面的例子中,键类型是string,值类型是int
map[string]int
声明一个 Map
map 也可以使用 var 关键字声明,但它会创建一个 nil map,因为 map 的默认零值是 nil。向该 map 添加任何键值对将导致恐慌。让我们看看这个例子
package main
func main() {
var employeeSalary map[string]int
employeeSalary["Tom"] = 2000
}
输出
panic: assignment to entry in nil map
上面的程序因 map 为 nil 而导致恐慌。
使用var关键字声明 map 的一个用例是当需要将一个已存在的 map 赋值给它或当我们想要赋值函数的结果时。
创建一个 Map
创建 map 的两种方式
-
使用 map[<key_type>]<value_type>{}格式也称为 map 字面量
-
使用 make
让我们逐一看看上述每种方法。
使用 map[<key_type>]<value_type>格式
创建 map 的最常见方式之一是使用 map 字面量:
map[key_type]value_type{}
上述例子的键类型是字符串,值类型是整数
employeeSalary := map[string]int{}
map 也可以创建并初始化一些键值
employeeSalary := map[string]int{
"John": 1000
"Sam": 2000
}
也可以向 map 中添加键值对
employeeSalary["Tom"] = 2000
让我们看看一个程序
package main
import "fmt"
func main() {
//Declare
employeeSalary := map[string]int{}
fmt.Println(employeeSalary)
//Intialize using map lieteral
employeeSalary = map[string]int{
"John": 1000,
"Sam": 1200,
}
//Adding a key value
employeeSalary["Tom"] = 2000
fmt.Println(employeeSalary)
}
输出
map[]
map[John:1000 Sam:1200 Tom:2000]
在上面的程序中,我们创建了一个初始化为某些值的 map 字面量。然后我们在其中添加了另一个键值对。接着我们使用fmt.Println打印它,以格式 map[key:value key:value]打印所有的键值对。
使用 Make
这是创建 map 的另一种方式。内置函数make可用于创建 map。它返回一个初始化的 map。因此可以向其中添加键值对。
package main
import "fmt"
func main() {
//Declare
employeeSalary := make(map[string]int)
//Adding a key value
employeeSalary["Tom"] = 2000
fmt.Println(employeeSalary)
}
输出
map[Tom:2000]
在上面的程序中,我们使用 make 函数创建了一个 map。然后我们在其中添加了一个键值对。接着我们使用fmt.Println打印它,打印出所有的键值对。
在 Go (Golang)中创建或初始化一个新字符串
目录
** 概览
- 程序
概览
下面是一种简单的方法来初始化或创建一个 Go 中的字符串。在下面的程序中,我们简单地声明并定义了一个名为sample的字符串。
注意语法
sample := "test"
这是完整的程序
程序
package main
import "fmt"
func main() {
sample := "test"
fmt.Println(sample)
}
输出
test
如果我们只想声明一个字符串变量,下面就是方法。声明的字符串会初始化为空字符串。
package main
import "fmt"
func main() {
var sample string
fmt.Println(sample)
}
输出
注意: 请查看我们的 Golang 高级教程。本系列教程内容详尽,我们尝试覆盖所有概念及示例。此教程适合希望获得专业知识和扎实理解 Golang 的人士 – Golang 高级教程
如果你有兴趣了解所有设计模式如何在 Golang 中实现。如果是,那么这篇文章就是为你准备的 –
注意: 请查看我们的系统设计教程系列 系统设计问题*
通过在 Go (Golang) 中调用恐慌函数创建恐慌
目录
-
概述
-
示例
概述
Go 提供了一个特殊函数来创建恐慌。下面是该函数的语法
func panic(v interface{})
此函数可以由程序员显式调用以创建恐慌。它接受一个空接口作为参数。
在程序员可以显式调用恐慌函数的一些情况包括:
-
函数期望一个有效的参数,但却提供了一个 nil 参数。在这种情况下,程序无法继续,并且会因传入 nil 参数而引发恐慌。
-
程序无法继续的任何其他情况。
示例
让我们看一个例子
package main
import "fmt"
func main() {
a := []string{"a", "b"}
checkAndPrint(a, 2)
}
func checkAndPrint(a []string, index int) {
if index > (len(a) - 1) {
panic("Out of bound access for slice")
}
fmt.Println(a[index])
}
输出
panic: runtime error: index out of range [2] with length 2
goroutine 1 [running]:
main.checkAndPrint(0xc00009af58, 0x2, 0x2, 0x2)
main.go:15 +0x31
main.main()
main.go:8 +0x7d
exit status 2
在上面的程序中,我们再次有一个函数 checkAndPrint,它接受一个切片作为参数和一个索引。然后它检查传入的索引是否大于切片长度减去 1。如果是,那么它就是超出切片边界的访问,因此会引发恐慌。如果不是,则打印该索引处的值。再注意输出中有两件事
-
错误信息
-
发生恐慌时的堆栈跟踪
在 Go (Golang)中创建浮点切片或数组。
目录。
** 概述
-
浮点切片
-
浮点数组
概述
在 Golang 中也可以创建浮点数据类型的切片或数组。实际上,任何数据类型都可以在 Go 中创建切片或数组。本教程包含创建浮点数据类型切片或数组的简单示例。
在此补充说明,Golang 中的数组大小是固定的,而切片可以具有可变大小。更多详情请见这里。
数组 – golangbyexample.com/understanding-array-golang-complete-guide/
切片 – golangbyexample.com/slice-in-golang/
。
浮点切片
package main
import "fmt"
func main() {
//First Way
var floats_first []float64
floats_first = append(floats_first, 1.1)
floats_first = append(floats_first, 2.2)
floats_first = append(floats_first, 3.3)
fmt.Println("Output for First slice of floats")
for _, c := range floats_first {
fmt.Println(c)
}
//Second Way
floats_second := make([]float64, 3)
floats_second[0] = 3.3
floats_second[1] = 2.2
floats_second[2] = 1.1
fmt.Println("\nOutput for Second slice of floats")
for _, c := range floats_second {
fmt.Println(c)
}
}
输出
Output for First slice of floats
1.1
2.2
3.3
Output for Second slice of floats
3.3
2.2
1.1
我们有两种创建浮点切片的方法。第一种方法是
var floats_first []float64
floats_first = append(floats_first, 1.1)
floats_first = append(floats_first, 2.2)
floats_first = append(floats_first, 3.3)
在第二种方法中,我们使用 make 命令来创建浮点切片。
floats_second := make([]float64, 3)
floats_second[0] = 3.3
floats_second[1] = 2.2
floats_second[2] = 1.1
浮点数组
package main
import "fmt"
func main() {
var floats_first [3]float64
floats_first[0] = 1.1
floats_first[1] = 2.2
floats_first[2] = 3.3
fmt.Println("Output for First Array of floats")
for _, c := range floats_first {
fmt.Println(c)
}
floats_second := [3]float64{
3.3,
2.2,
1.1,
}
fmt.Println("\nOutput for Second Array of floats")
for _, c := range floats_second {
fmt.Println(c)
}
}
输出
Output for First Array of floats
1.1
2.2
3.3
Output for Second Array of floats
3.3
2.2
1.1
我们有两种创建数组的方法。第一种方法是
var floats_first [3]float64
floats_first[0] = 1.1
floats_first[1] = 2.2
floats_first[2] = 3.3
在第二种方法中,我们直接用创建的浮点数初始化数组。
floats_second := [3]float64{
3.3,
2.2,
1.1,
}
请查看我们的 Golang 高级教程。本系列教程内容详尽,我们尽力涵盖所有概念和示例。本教程适合希望获得专业知识和对 Golang 有深入理解的读者 – Golang 高级教程。
如果您有兴趣了解如何在 Golang 中实现所有设计模式。如果是的话,这篇文章适合您 – 所有设计模式 Golang。
在 Go 中创建整数的切片或数组(Golang)
目录
-
概述**
-
整数切片
-
整数数组
概述
在 Golang 中也可以创建int数据类型的切片或数组。实际上,Go 中可以创建任何数据类型的切片或数组。本教程包含简单的示例,演示如何在 Golang 中创建 int 数据类型的切片或数组。
这里补充一下,在 Golang 中数组是固定大小的,而切片可以有可变大小。更多细节在这里
数组 – golangbyexample.com/understanding-array-golang-complete-guide/
切片 – golangbyexample.com/slice-in-golang/
整数切片
package main
import "fmt"
func main() {
//First Way
var integers_first []int
integers_first = append(integers_first, 1)
integers_first = append(integers_first, 2)
integers_first = append(integers_first, 3)
fmt.Println("Output for First slice of integers")
for _, c := range integers_first {
fmt.Println(c)
}
//Second Way
integers_second := make([]int, 3)
integers_second[0] = 3
integers_second[1] = 2
integers_second[2] = 1
fmt.Println("\nOutput for Second slice of integers")
for _, c := range integers_second {
fmt.Println(c)
}
}
输出
Output for First slice of integers
1
2
3
Output for Second slice of integers
3
2
1
我们有两种创建整数切片的方法。第一种方法是
var integers_first []int
integers_first = append(integers_first, 1)
integers_first = append(integers_first, 2)
integers_first = append(integers_first, 3)
在第二种方法中,我们使用 make 命令来创建整数切片
integers_second := make([]int, 3)
integers_second[0] = 3
integers_second[1] = 2
integers_second[2] = 1
无论哪种方法都可以。这就是我们如何创建整数切片
整数数组
package main
import "fmt"
func main() {
var integers_first [3]int
integers_first[0] = 1
integers_first[1] = 2
integers_first[2] = 3
fmt.Println("Output for First Array of integers")
for _, c := range integers_first {
fmt.Println(c)
}
integers_second := [3]int{
3,
2,
1,
}
fmt.Println("\nOutput for Second Array of integers")
for _, c := range integers_second {
fmt.Println(c)
}
}
输出
Output for First Array of integers
1
2
3
Output for Second Array of integers
3
2
1
我们有两种创建数组的方法。第一种方法是
var integers_first [3]int
integers_first[0] = 1
integers_first[1] = 2
integers_first[2] = 3
在第二种方法中,我们直接用创建的整数初始化数组
integers_second := [3]int{
3,
2,
1,
}
查看我们的 Golang 高级教程。本系列教程详尽,我们努力覆盖所有概念及示例。本教程适合那些希望获得专业知识和扎实理解 Golang 的人 – Golang 高级教程
如果你有兴趣了解所有设计模式如何在 Golang 中实现。如果是的话,这篇文章适合你 –所有设计模式 Golang
在 Go (Golang)中创建字符串切片或数组
目录
-
概述
-
字符串切片
-
字符串数组
概述
在 Golang 中,也可以创建string数据类型的切片或数组。实际上,Go 中可以创建任何数据类型的切片或数组。本教程包含创建string数据类型的切片或数组的简单示例。
这里补充一下,在 golang 中,数组是固定大小的,而切片可以有可变大小。更多详细信息请查看这里。
数组 – golangbyexample.com/understanding-array-golang-complete-guide/
切片 – golangbyexample.com/slice-in-golang/
字符串切片
package main
import "fmt"
func main() {
//First Way
var string_first []string
string_first = append(string_first, "abc")
string_first = append(string_first, "def")
string_first = append(string_first, "ghi")
fmt.Println("Output for First slice of string")
for _, c := range string_first {
fmt.Println(c)
}
//Second Way
string_second := make([]string, 3)
string_second[0] = "ghi"
string_second[1] = "def"
string_second[2] = "abc"
fmt.Println("\nOutput for Second slice of string")
for _, c := range string_second {
fmt.Println(c)
}
}
输出
Output for First slice of string
abc
def
ghi
Output for Second slice of string
ghi
def
abc
我们有两种创建字符串切片的方法。第一种方法是
var string_first []string
string_first = append(string_first, "abc")
string_first = append(string_first, "def")
string_first = append(string_first, "ghi")
在第二种方法中,我们使用 make 命令来创建字符串切片。
string_second := make([]string, 3)
string_second[0] = "ghi"
string_second[1] = "def"
string_second[2] = "abc"
无论哪种方式都可以。这是我们创建字符串切片的方法。
字符串数组
package main
import "fmt"
func main() {
var string_first [3]string
string_first[0] = "abc"
string_first[1] = "def"
string_first[2] = "ghi"
fmt.Println("Output for First Array of string")
for _, c := range string_first {
fmt.Println(c)
}
string_second := [3]string{
"ghi",
"def",
"abc",
}
fmt.Println("\nOutput for Second Array of string")
for _, c := range string_second {
fmt.Println(c)
}
}
输出
Output for First Array of string
abc
def
ghi
Output for Second Array of string
ghi
def
abc
我们有两种创建数组的方法。第一种方法是
var string_first [3]string
string_first[0] = "abc"
string_first[1] = "def"
string_first[2] = "ghi"
在第二种方法中,我们直接用一些字符串初始化数组。
string_second := [3]string{
"ghi",
"def",
"abc",
}
查看我们的 Golang 高级教程。本系列的教程内容详尽,尽力涵盖所有概念及示例。本教程适合那些希望掌握 golang 并深入理解的读者 – Golang 高级教程
如果你有兴趣了解所有设计模式如何在 Golang 中实现。如果是的话,这篇文章就是为你准备的 – 所有设计模式 Golang
在 Go (Golang) 中的数字立方根
目录
-
概述
-
代码:
概述
GO 的 math 包提供了一个 Cbrt 方法,可以用于获取该数字的立方根。
以下是该函数的签名。它接受一个浮点数作为输入,并返回一个浮点数。
func Cbrt(x float64) float64
Cbrt 函数的一些特殊情况是
-
Cbrt(±0) = ±0
-
Cbrt(±Inf) = ±Inf
-
Cbrt(NaN) = NaN
代码:
package main
import (
"fmt"
"math"
)
func main() {
res := math.Cbrt(8)
fmt.Println(res)
res = math.Cbrt(27)
fmt.Println(res)
res = math.Cbrt(30.33)
fmt.Println(res)
}
输出:
2
3
3.118584170228812
Go 语言中的当前时间戳
目录
概述
- 代码
概述
在本教程中,我们将看到如何使用 Go 语言中的 time 包获取当前时间戳。当前时间可以用不同的方式表示。
- time.Time对象
t := time.Now() //It will return time.Time object with current timestamp
- Unix 时间(也称为纪元时间) – 它是自 1970 年 1 月 1 日 00:00:00 UTC 以来经过的秒数。这个时间也被称为 Unix 纪元。
t := time.Now().Unix()
//Will return number of seconds passed since Unix epoch
- Unix 纳秒 – 自 1970 年 1 月 1 日 00:00:00 UTC 以来经过的纳秒数
t := time.Now().UnixNano()
//Will return number of nano seconds passed since Unix epoch
- Unix 毫秒 – 自 1970 年 1 月 1 日 00:00:00 UTC 以来经过的毫秒数
t:= int64(time.Nanosecond) * t.UnixNano() / int64(time.Millisecond)/ time.Millisecond
//Number of millisecond elapsed since Unix epoch
- Unix 微秒 – 自 1970 年 1 月 1 日 00:00:00 UTC 以来经过的微秒数
t:= int64(time.Nanosecond) * t.UnixNano() / int64(time.Millisecond)/ time.Millisecond
//Number of millisecond elapsed since Unix epoch
代码
package main
import (
"fmt"
"time"
)
func main() {
t := time.Now() //It will return time.Time object with current timestamp
fmt.Printf("time.Time %s\n", t)
tUnix := t.Unix()
fmt.Printf("timeUnix: %d\n", tUnix)
tUnixNano := t.UnixNano()
fmt.Printf("timeUnixNano: %d\n", tUnixNano)
tUnixMilli := int64(time.Nanosecond) * t.UnixNano() / int64(time.Millisecond)
fmt.Printf("timeUnixMilli: %d\n", tUnixMilli)
tUnixMicro := int64(time.Nanosecond) * t.UnixNano() / int64(time.Microsecond)
fmt.Printf("timeUnixMicro: %d\n", tUnixMicro)
}
输出:
time.Time 2020-01-24 09:43:42.196901 UTC m=+0.000229700
timeUnix: 1579839222
timeUnixNano: 1579839222196901000
timeUnixMilli: 1579839222196
timeUnixMicro: 1579839222196901
Go (Golang) 中的 defer 中的自定义函数
目录
-
概述
-
示例
概述
我们也可以在 defer 中调用自定义函数。让我们来看一个示例
示例
package main
import "fmt"
func main() {
defer test()
fmt.Println("Executed in main")
}
func test() {
fmt.Println("In Defer")
}
输出
Executed in main
In Defer
在上述程序中,有一个defer语句调用了名为test的自定义函数。从输出可以看到,test函数在主函数中的所有操作执行完毕后被调用,并在主函数返回之前调用。这就是为什么
Executed in main
会在之前打印
In Defer
上述函数还显示在主函数中使用 defer 是完全可以的。
Go 中的日期 (Golang)
在 Go 中,日期仅通过 time.Time 结构表示。Go 中没有单独的 Date 结构。可以使用 time.Date 函数构造日期。该函数返回格式为 yyyy-mm-dd hh:mm:ss + nsec 的时间,包含与给定位置对应的适当时区。函数的签名是:
func Date(year int, month Month, day, hour, min, sec, nsec int, loc *Location) Time
从签名中可以看出,函数的参数是
-
年
-
月
-
天
-
小时
-
分
-
秒
-
毫秒
-
位置
关于 time.Date 函数的一些注意事项
-
如果传入的位置信息为 nil,Date 函数将会引发 panic。
-
月、日、时、分、秒、纳秒值会被规范化。因此,如果传入的月份是 14,它将被转换为 2。
让我们看看一个工作示例:
package main
import (
"fmt"
"time"
)
func main() {
t := time.Date(2021, time.Month(2), 21, 1, 10, 30, 0, time.UTC)
fmt.Println(t)
}
输出:
2021-02-21 01:10:30 +0000 UTC
在 Go(Golang)中声明/初始化/创建数组或切片
来源:
golangbyexample.com/declare-initialize-create-array-slice-golang/
目录
概述
-
创建切片
-
从另一个切片或数组创建切片
-
从数组创建切片
-
从切片创建切片
-
-
使用 make 函数
-
使用新函数
-
创建数组 *# 概述
与其他编程语言类似,Golang 也有数组数据结构。但在 Go 中,数组的行为与其他语言略有不同,我们还有一种叫切片的结构,它类似于数组的引用。切片比数组更强大且更方便使用。事实上,切片在其他编程语言中更类似于数组。
在这篇文章中,我们将学习如何
-
创建切片实例
-
创建数组实例
创建切片
创建切片的方式有四种
-
使用 []<类型>{} 格式
-
从另一个切片或数组创建切片
-
使用 make
-
使用新方法
让我们逐一查看上述每种方法。
使用 []<类型>{} 格式
声明切片的最常见方式是这样的
s := []int
它声明了一个长度为 0、容量为 0 的空切片。我们也可以在声明时初始化切片。
s := []int{1,2}
它声明了一个长度为 2、容量也为 2 的整数切片。容量等于实际指定的切片元素数量。我们还有两个由 Go 提供的库函数可以用来获取切片的 长度 和 容量。
-
len() 函数 – 用于切片的长度
-
cap() 函数 – 用于切片的容量
让我们看看一个小程序,展示以上几点。
package main
import "fmt"
func main() {
sample := []int{}
fmt.Println(len(sample))
fmt.Println(cap(sample))
fmt.Println(sample)
letters := []string{"a", "b", "c"}
fmt.Println(len(letters))
fmt.Println(cap(letters))
fmt.Println(letters)
}
输出
0
0
[]
3
3
[a b c]
当实际元素未指定时,切片的长度和容量均为零。当指定实际元素时,长度和容量等于指定的实际元素数量。
从另一个切片或数组创建切片
切片可以通过重新切片现有切片或数组来创建。
从数组创建切片
通过重新切片现有数组创建新切片的格式为
[n]sample[start:end]
上述操作将返回一个新切片,从数组的索引 start 开始到索引 end-1。因此,索引 end 的元素不包含在新创建的切片中。在重新切片时,起始和结束索引都是可选的。
-
起始索引的默认值为零
-
结束索引的默认值是数组的长度。
让我们看看一个例子。
package main
import "fmt"
func main() {
numbers := [5]int{1, 2, 3, 4, 5}
//Both start and end
num1 := numbers[2:4]
fmt.Println("Both start and end")
fmt.Printf("num1=%v\n", num1)
fmt.Printf("length=%d\n", len(num1))
fmt.Printf("capacity=%d\n", cap(num1))
//Only start
num2 := numbers[2:]
fmt.Println("\nOnly start")
fmt.Printf("num1=%v\n", num2)
fmt.Printf("length=%d\n", len(num2))
fmt.Printf("capacity=%d\n", cap(num2))
//Only end
num3 := numbers[:3]
fmt.Println("\nOnly end")
fmt.Printf("num1=%v\n", num3)
fmt.Printf("length=%d\n", len(num3))
fmt.Printf("capacity=%d\n", cap(num3))
//None
num4 := numbers[:]
fmt.Println("\nOnly end")
fmt.Printf("num1=%v\n", num4)
fmt.Printf("length=%d\n", len(num4))
fmt.Printf("capacity=%d\n", cap(num4))
}
输出
Both start and end
num1=[3 4]
length=2
capacity=3
Only start
num1=[3 4 5]
length=3
capacity=3
Only end
num1=[1 2 3]
length=3
capacity=5
Only end
num1=[1 2 3 4 5]
length=5
capacity=5
请注意上面的例子中:
-
新创建切片的长度 = (end–start)
-
新创建切片的容量 = (length_of_array–start)
num1切片的样子如下。
新创建的切片仍然引用原始数组。要检查这一点,可以在数组的任意索引处更改元素,然后重新打印切片。
numbers[3] = 8
fmt.Printf("num1=%v\n", num2)
fmt.Printf("num3=%v\n", num3)
fmt.Printf("num4=%v\n", num4)
输出如下:
num1=[3 8 5]
num3=[1 2 3 8]
num4=[1 2 3 8 5]
这证明每个新切片仍然引用原始数组。
从切片创建切片
我们关于从数组重新切片的讨论同样适用于这里。请参见下面的例子以说明同样的内容。
package main
import "fmt"
func main() {
numbers := []int{1, 2, 3, 4, 5}
//Both start and end
num1 := numbers[2:4]
fmt.Println("Both start and end")
fmt.Printf("num1=%v\n", num1)
fmt.Printf("length=%d\n", len(num1))
fmt.Printf("capacity=%d\n", cap(num1))
//Only start
num2 := numbers[2:]
fmt.Println("\nOnly start")
fmt.Printf("num1=%v\n", num2)
fmt.Printf("length=%d\n", len(num2))
fmt.Printf("capacity=%d\n", cap(num2))
//Only end
num3 := numbers[:3]
fmt.Println("\nOnly end")
fmt.Printf("num1=%v\n", num3)
fmt.Printf("length=%d\n", len(num3))
fmt.Printf("capacity=%d\n", cap(num3))
//None
num4 := numbers[:]
fmt.Println("\nOnly end")
fmt.Printf("num1=%v\n", num4)
fmt.Printf("length=%d\n", len(num4))
fmt.Printf("capacity=%d\n", cap(num4))
}
输出
Both start and end
num1=[3 4]
length=2
capacity=3
Only start
num1=[3 4 5]
length=3
capacity=3
Only end
num1=[1 2 3]
length=3
capacity=5
Only end
num1=[1 2 3 4 5]
length=5
capacity=5
在这里,新创建的切片也引用与原始切片所引用的相同基础数组。要检查这一点,可以在原始切片的任意索引处更改元素,然后重新打印所有新创建的切片。
numbers[3] = 8
fmt.Printf("num1=%v\n", num2)
fmt.Printf("num3=%v\n", num3)
fmt.Printf("num4=%v\n", num4)
使用 make 函数
make是 Go 提供的一个内置函数,也可以用来创建切片。以下是 make 函数的签名。
func make([]{type}, length, capacity int) []{type}
创建切片时,make
函数的容量是一个可选参数。当省略容量时,切片的容量等于指定的长度。使用make
函数时,Go 背后会分配一个与容量相等的数组。分配的数组的所有元素都初始化为该类型的默认零值。让我们看看一个说明这一点的程序。
package main
import "fmt"
func main() {
numbers := make([]int, 3, 5)
fmt.Printf("numbers=%v\n", numbers)
fmt.Printf("length=%d\n", len(numbers))
fmt.Printf("capacity=%d\n", cap(numbers))
//With capacity ommited
numbers = make([]int, 3)
fmt.Println("\nCapacity Ommited")
fmt.Printf("numbers=%v\n", numbers)
fmt.Printf("length=%d\n", len(numbers))
fmt.Printf("capacity=%d\n", cap(numbers))
}
输出
numbers=[0 0 0]
length=3
capacity=5
With Capacity Ommited
numbers=[0 0 0]
length=3
capacity=3
使用 new 函数
new是 Go 提供的一个内置函数,也可以用来创建切片。这种创建切片的方式并不常用,因为make在功能上更加灵活。一般情况下不常使用,并且使用new函数会返回指向 nil 切片的指针。让我们看一个例子。在下面的例子中,我们使用解引用操作符‘*’,因为new函数返回指向 nil 切片的指针。
package main
import "fmt"
func main() {
numbers := new([]int)
fmt.Printf("numbers=%v\n", *numbers)
fmt.Printf("length=%d\n", len(*numbers))
fmt.Printf("capacity=%d\n", cap(*numbers))
}
输出
numbers=[]
length=0
capacity=0
创建一个数组
数组声明中的元素数量和实际元素都是可选的。
在下面的例子中,我们看到创建数组的 4 种方式。
- 同时指定数组的长度和实际元素。例如:
[2]int{1, 2}
- 仅长度——在这种情况下,所有实际元素都填充为该类型的默认值零。例如:
[2]int{}
- 仅实际元素——在这种情况下,数组的长度将等于实际元素的数量。符号‘…’在不指定长度时需要在方括号内使用,例如[…]。该符号是指令,指示编译器计算长度。
[...]int{2, 3}
- 没有长度和实际元素——在这种情况下,将创建一个空数组。与上述相似,符号‘…’在这种情况下也需要使用。
[...]int{}
让我们看一个代码示例来说明上述要点。还请记住,可以使用内置函数len()来计算数组的长度。在下面的程序中,我们使用len()函数来计算数组的长度。
package main
import "fmt"
func main() {
//Both number of elements and actual elements
sample1 := [2]int{1, 2}
fmt.Printf("Sample1: Len: %d, %v\n", len(sample1), sample1)
//Only actual elements
sample2 := [...]int{2, 3}
fmt.Printf("Sample2: Len: %d, %v\n", len(sample2), sample2)
//Only number of elements
sample3 := [2]int{}
fmt.Printf("Sample3: Len: %d, %v\n", len(sample3), sample3)
//Without both number of elements and actual elements
sample4 := [...]int{}
fmt.Printf("Sample4: Len: %d, %v\n", len(sample4), sample4)
}
输出
Sample1: Len: 2, [1 2]
Sample2: Len: 2, [2 3]
Sample3: Len: 2, [0 0]
Sample4: Len: 0, []
请注意,上述示例中,对于sample3变量,实际元素用默认值 0 填充。
如果指定的实际元素少于数组的长度也是可以的。其余元素将用指定类型的默认值填充。请参见下面的示例。指定的数组长度为 4,而只有 2 个实际元素被声明。因此,剩余的两个元素被赋值为 0,这是int的默认零值。
package main
import "fmt"
func main() {
sample := [4]int{5, 8}
fmt.Printf("Sample: Len: %d, %v\n", len(sample), sample)
}
输出
Sample: Len: 4, [5 8 0 0]