From a5ef0b27faac43ac32530db5d8b003eec67448da Mon Sep 17 00:00:00 2001 From: RickyWang1020 <50431019+RickyWang1020@users.noreply.github.com> Date: Wed, 26 Aug 2020 10:08:42 +0800 Subject: [PATCH 1/4] Update golang_tutorial_12.md --- docs/golang_tutorial_12.md | 99 ++++++++++++++++++++++++++++++++------ 1 file changed, 85 insertions(+), 14 deletions(-) diff --git a/docs/golang_tutorial_12.md b/docs/golang_tutorial_12.md index d1b6104..1f90158 100644 --- a/docs/golang_tutorial_12.md +++ b/docs/golang_tutorial_12.md @@ -2,19 +2,50 @@ ======================== 上一节:[第十一篇 数组和切片](/docs/golang_tutorial_11.md) -下一节:[第十三篇 包](/docs/golang_tutorial_13.md) +下一节:[第十三篇 Map](/docs/golang_tutorial_13.md) 这是本Golang系列教程的第12篇。 ## 什么是变参函数? -变参函数是指可以接受可变数量的参数的函数。 +变参函数是指可以接收可变数量的参数的函数。 -## 语法? +如果一个函数的最后一个参数由 `...T` 表示,则表示该函数可以接收任意数量的类型为 T 的参数。 -如果一个函数的最后一个参数由 `...T` 表示,则表示该函数可以接受任意数量的类型为 T 的参数。 +请注意只有函数的最后一个参数才能指定为可变参数。 -请注意只有函数的最后一个参数才能指定为可变参数。 +## 语法 + +```golang +func hello(a int, b ...int){ +} +``` + +上述函数中,`b` 就是一个可变参数,因为它的类型定义有 `...` 前缀,因而可以接收任意数量的输入。以下语句可以用来调用这个变参函数: + +```golang +hello(1, 2) //passing one argument "2" to b +hello(5, 6, 7, 8, 9) //passing arguments "6, 7, 8 and 9" to b +``` + +第一行中,我们将 `2` 赋给了 `b` ;第二行中,我们将四个参数 `6, 7, 8, 9` 赋给了 `b`。 + +我们也可以选择不将参数传入变参函数(即:传入“零”个参数),例如: + +```golang +hello(1) +``` + +我们调用了 `hello` 函数,但是没有为 `b` 传入任何参数,这也是完全可以的。 + +为什么变参函数中的可变参数必须在定义参数时放在最后?作为反例,我们来尝试将 `hello` 函数的第一个参数变成可变参数: + +```golang +func hello(b ...int, a int){ +} +``` + +以上函数中,我们将无法为 `a` 传入参数, 因为无论我们在函数中传入多少参数,这些参数都会被赋给可变参数 `b`。上述函数会出现编译错误:`syntax error: cannot use ... with non-final parameter b`,因此可变参数必须在定义参数时被放在最后。 ## 案例 @@ -51,7 +82,9 @@ func main() { } ``` -上面的程序中,`func find(num int, nums ...int) `可以接受任意数量的参数。`...int `在内部表示为切片。在这里 `nums` 的类型为 `[]int`。 +上面的程序中,`func find(num int, nums ...int)` 可以为 `nums` 接收任意数量的参数。在函数内部,`nums` 的类型为 `[]int`,即整数切片类型。 + +**变参函数会将可变数量的参数转换成相应类型的切片,例如上述函数的第22行,传入 `find` 函数的可变参数是 89,90,95,随后这些参数会被编译器转换为整数切片 `[]int{89, 90, 95}` 然后被送入 `find` 函数内。** 第 10 行利用 `range for` 遍历 `nums` 切片,如果找到 num 则打印 num 所在位置,否则打印没有找到。 @@ -71,11 +104,52 @@ type of nums is []int 87 not found in [] ``` -在第 25 行,`find `只有一个参数。我们没有传递任何参数给 `nums ...int`。这是合法的,(译者注:如果没有给可变参数传递任何值,则可变参数为 `nil `切片),在这里 `nums `是一个 `nil `切片,长度和容量都是`0`。 +在第 25 行,`find `只有一个参数。我们没有传递任何参数给 `nums ...int`。这是合法的,(译者注:如果没有给可变参数传递任何值,则可变参数为 `nil` 切片),在这里 `nums` 是一个 `nil` 切片,长度和容量都是`0`。 + +## 切片 VS 可变参数 + +我们现在肯定会想到一个问题:既然传入的可变参数被转换成了切片,那么我们为何不直接将一个切片传入函数中呢?我们将之前的函数用切片参数来改写: + +```golang +package main + +import ( + "fmt" +) + +func find(num int, nums []int) { + fmt.Printf("type of nums is %T\n", nums) + found := false + for i, v := range nums { + if v == num { + fmt.Println(num, "found at index", i, "in", nums) + found = true + } + } + if !found { + fmt.Println(num, "not found in ", nums) + } + fmt.Printf("\n") +} +func main() { + find(89, []int{89, 90, 95}) + find(45, []int{56, 67, 45, 90, 109}) + find(78, []int{38, 56, 98}) + find(87, []int{}) +} +``` + +用可变参数代替切片的优势如下: + +1. 不用在每次调用函数时都创建一个新的切片。上述函数中,我们在第22、23、24、25行都创建了新的切片,如果使用变参函数,这些额外的切片创建就可以省略。 -## 传递切片给可变参数 +2. 在第25行,为了满足 `find` 函数的参数定义,我们创建了一个空的切片,在变参函数中,我们只需要写 `find(87)` 即可。 -我们已经提到 `...T `在内部表示为类型是 `[]T` 切片。如果真是这样,可以传递一个切片给可变参数吗?让我们从下面的例子中寻找答案: +3. 我(原文作者)认为带变参函数的程序比带切片的函数可读性强 :) + +## 将切片传入可变参数 + +我们已经提到 `...T` 在内部表示为类型是 `[]T` 切片。如果真是这样,可以传递一个切片给可变参数吗?让我们从下面的例子中寻找答案: ```golang package main @@ -104,9 +178,9 @@ func main() { } ``` -在第 23 行,我们没有将若干数量的参数传递给 `find` 的最后一个参数, 而是传递了一个切片。这是非法的,我们不能传递一个切片给可变参数。上面的程序将报错:`main.go:23: cannot use nums (type []int) as type int in argument to find`。 +在第 23 行,我们没有将若干数量的参数传递给 `find` 函数的最后一个参数, 而是传递了一个切片。这是非法的,我们不能传递一个切片给可变参数。上面的程序将报错:`main.go:23: cannot use nums (type []int) as type int in argument to find`。 -这里有一个语法糖可以用来将切片传递给变参函数。可以在切片后面加 `...`,这样会将切片展开为其中的各个元素并将它们传递给变参函数。这样该程序将正常工作。 +**有一个语法糖可以用来将切片传递给变参函数:在切片后面加 `...`,这样会将切片展开为其中的各个元素并将它们传递给变参函数,程序将正常工作。** 上面的程序如果将第23行的 `find(89, nums)` 改为` find(89, nums...)`,程序将通过编译,并输出如下: @@ -116,6 +190,3 @@ type of nums is []int ``` 变参函数的介绍到此结束。感谢阅读。 - -上一节:[第十一篇 数组和切片](/docs/golang_tutorial_10.md) -下一节:[第十三篇 Map](/docs/golang_tutorial_12.md) From b34844a8dcf746ba6fbffbe1ca07621f946a4c95 Mon Sep 17 00:00:00 2001 From: RickyWang1020 <50431019+RickyWang1020@users.noreply.github.com> Date: Wed, 26 Aug 2020 11:09:23 +0800 Subject: [PATCH 2/4] Update golang_tutorial_13.md --- docs/golang_tutorial_13.md | 93 +++++++++++++++++++++++++++++++------- 1 file changed, 77 insertions(+), 16 deletions(-) diff --git a/docs/golang_tutorial_13.md b/docs/golang_tutorial_13.md index 054a0bb..679274b 100644 --- a/docs/golang_tutorial_13.md +++ b/docs/golang_tutorial_13.md @@ -1,4 +1,4 @@ -13 - Map 集合 +13 - Map ======================== 上一节:[第十二篇 变参函数](/docs/golang_tutorial_12.md) @@ -8,9 +8,9 @@ ## 什么是 map? -Map 是 Go 中的内置类型,它将键与值绑定到一起。可以通过键获取相应的值。 +Map 是 Go 中的内置类型,它将键与值绑定到一起。可以通过键获取相应的值。Map与其他语言(例如Python)中的dictionary非常相似。 -## 如何创建 map? +## 如何创建 map? 可以通过将键和值的类型传递给内置函数 `make` 来创建一个 `map`。语法为:`make(map[KeyType]ValueType)`。(译者注:`map` 的类型表示为 `map[KeyType]ValueType`)例如: @@ -18,9 +18,9 @@ Map 是 Go 中的内置类型,它将键与值绑定到一起。可以通过键 personSalary := make(map[string]int) ``` -上面的代码创建了一个名为 `personSalary` 的 map。其中键的类型为 string,值的类型为 int。 +上面的代码创建了一个名为 `personSalary` 的 map。其中键的类型为 `string`,值的类型为 `int`。 -**map 的 0 值为 `nil`。试图给一个 nil map 添加元素给会导致运行时错误。因此 map 必须通过 make 来初始化** (译者注:也可以使用速记声明来创建 map,见下文)。 +**map 的 0 值为 `nil`。试图给一个 nil map 添加元素给会导致运行时错误。因此 map 必须通过 `make` 来初始化** (译者注:也可以使用速记声明来创建 map,见下文)。 ```golang package main @@ -42,7 +42,8 @@ func main() { ## 向 map 中插入元素 -插入元素给 map 的语法与数组相似。下面的代码插入一些新的元素给 `map personSalary`。 +插入元素给 map 的语法与数组相似。下面的代码插入一些新的元素给名为 `personSalary` 的 map。 + ```golang package main @@ -61,7 +62,7 @@ func main() { 上面的程序输出:`personSalary map contents: map[steve:12000 jamie:15000 mike:9000]`。 -也可以在声明时初始化一个数组: +也可以在声明时初始化一个 map: ```golang package main @@ -86,7 +87,7 @@ func main() { personSalary map contents: map[steve:12000 jamie:15000 mike:9000] ``` -`string` 并不是可以作为键的唯一类型,其他所有可以比较的类型,比如,布尔类型,整型,浮点型,复数类型都可以作为键。如果你想了解更多关于可比较类型的话,请参阅:http://golang.org/ref/spec#Comparison_operators +`string` 并不是可以作为键的唯一类型,其他所有可以比较的类型,比如,布尔类型,整型,浮点型,复数类型都可以作为键。甚至用户自定义的类型,如 `struct`,也可以作为键。如果你想了解更多关于可比较类型的话,请参阅:http://golang.org/ref/spec#Comparison_operators ## 访问 map 中的元素 @@ -140,7 +141,7 @@ Salary of jamie is 15000 Salary of joe is 0 ``` -上面的程序返回 `joe` 的工资为` 0`。我们没有得到任何运行时错误说明键 joe 在 `personSalary` 中不存在。 +上面的程序返回 `joe` 的工资为` 0`。我们没有得到任何运行时错误说明键 `joe` 在 `personSalary` 中不存在。 我们如何检测一个键是否存在于一个 map 中呢?可以使用下面的语法: @@ -180,7 +181,9 @@ func main() { joe not found ``` -range for 可用于遍历 map 中所有的元素(译者注:这里 range 操作符会返回 map 的键和值)。 +## 遍历 map 中的所有元素 + +`for` 循环的 `range` 形式可用于遍历 map 中所有的元素(译者注:这里 `range` 操作符会返回 map 的键和值)。 ```golang package main @@ -193,8 +196,8 @@ func main() { personSalary := map[string]int{ "steve": 12000, "jamie": 15000, + "mike": 9000, } - personSalary["mike"] = 9000 fmt.Println("All items of a map") for key, value := range personSalary { fmt.Printf("personSalary[%s] = %d\n", key, value) @@ -211,11 +214,11 @@ personSalary[steve] = 12000 personSalary[jamie] = 15000 ``` -值得注意的是,因为 map 是无序的,因此对于程序的每次执行,不能保证使用 range for 遍历 map 的顺序总是一致的。 +值得注意的是,因为 map 是无序的,因此对于程序的每次执行,不能保证使用 `for range` 遍历 map 的顺序总是一致的,而且遍历的顺序也不完全与元素添加的顺序一致。 ## 删除元素 -`delete(map, key) `用于删除 map 中的 key。delete 函数没有返回值。 +`delete(map, key)` 用于删除 map 中的键。`delete` 函数没有返回值。 ```golang package main @@ -244,6 +247,62 @@ map before deletion map[steve:12000 jamie:15000 mike:9000] map after deletion map[mike:9000 jamie:15000] ``` +如果我们试图删除一个原 map 中不存在的键,运行 `delete` 时仍不会报错。 + +## 结构体 map (Map of Structs) + +目前我们编写了存储员工工资的 map,那么可否将员工的国籍也存储在 map 中呢?这可以通过结构体 map 来完成。每个员工可以用一个包含了“工资”和“国籍”的结构体来表示,这些结构体将被存储在一个键为 `string` 类型,值为 `struct` 类型的 map 中。 + +```golang +package main + +import ( + "fmt" +) + +type employee struct { + salary int + country string +} + +func main() { + emp1 := employee{ + salary: 12000, + country: "USA", + } + emp2 := employee{ + salary: 14000, + country: "Canada", + } + emp3 := employee{ + salary: 13000, + country: "India", + } + employeeInfo := map[string]employee{ + "Steve": emp1, + "Jamie": emp2, + "Mike": emp3, + } + + for name, info := range employeeInfo { + fmt.Printf("Employee: %s Salary:$%d Country: %s\n", name, info.salary, info.country) + } + +} +``` + +以上程序中,`employee` 结构体包含了 `salary` 和 `country`。 + +在第25行,我们创建了一个 map,键为字符串类型,值为 `employee` 结构体,并添加了我们创建的三个员工。 + +在第31行,我们遍历这个 map,打印出所有员工的信息: + +```golang +Employee: Mike Salary:$13000 Country: India +Employee: Steve Salary:$12000 Country: USA +Employee: Jamie Salary:$14000 Country: Canada +``` + ## map 的大小 用内置函数 `len` 获取 map 的大小: @@ -303,7 +362,7 @@ Person salary changed map[jamie:15000 mike:18000 steve:12000] ## 比较 map -map 不能通过 `== `操作符比较是否相等。`== `操作符只能用来检测 map 是否为 nil。 +map 不能通过 `==` 操作符比较是否相等。`==` 操作符只能用来检测 map 是否为 `nil`。 ```golang package main @@ -323,7 +382,7 @@ func main() { 上面的程序将会报错:`invalid operation: map1 == map2 (map can only be compared to nil)`。 -比较两个 map 是否相等的方式是一一比较它们的元素是否相等。我会鼓励你为此编写一个程序,使其工作:) +比较两个 map 是否相等的方式是一一比较它们的元素是否相等。希望你能自己探索并编写一个达成这一功能的程序:) 我(原文作者)已经将我们讨论的所有概念汇总到一个程序中,你可以从 [github](https://github.com/golangbot/arraysandslices) 下载。 @@ -363,6 +422,8 @@ func main(){ "school":"BAT_UN" } fmt.Println(m4) + + // 方式五 m5 := make(map[string][string]) m5["name"] = "Linux" m5["school"] = "Unix" @@ -397,7 +458,7 @@ func main(){ fmt.Println(m_b, ok) // OK b true // 迭代操作 - s_map := make([]map[int]string,5) // 以 map 为元素的slice 使用 make 创建一个切片,元素的slic + s_map := make([]map[int]string,5) // 以 map 为元素的 slice 使用 make 创建一个切片,切片内的每个元素为一个 map for _,v := range s_map { v = make(map[int]string) // v 是值的拷贝 v[1] = "OK" From ec29c425157aad9b9d6e0647e0cde2ff7766cc24 Mon Sep 17 00:00:00 2001 From: RickyWang1020 <50431019+RickyWang1020@users.noreply.github.com> Date: Wed, 26 Aug 2020 11:11:14 +0800 Subject: [PATCH 3/4] Update golang_tutorial_13.md --- docs/golang_tutorial_13.md | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/docs/golang_tutorial_13.md b/docs/golang_tutorial_13.md index 679274b..2164051 100644 --- a/docs/golang_tutorial_13.md +++ b/docs/golang_tutorial_13.md @@ -113,7 +113,7 @@ func main() { 上面的程序非常简单。员工 `jamie` 的工资被取出并打印。程序的输出为:`Salary of jamie is 15000`。 -如果一个键不存在会发生什么?`map` 会返回值类型的 `0 `值。比如如果访问了 `personSalary` 中的不存在的键,那么将返回 `int` 的 0 值,也就是 0。 +如果一个键不存在会发生什么?`map` 会返回值类型的 `0` 值。比如如果访问了 `personSalary` 中的不存在的键,那么将返回 `int` 的 0 值,也就是 0。 ```golang package main @@ -325,7 +325,7 @@ func main() { } ``` -上面程序中,`len(personSalary) `获取 `personSalary` 的大小。上面的程序输出:`length is 3`。 +上面程序中,`len(personSalary)` 获取 `personSalary` 的大小。上面的程序输出:`length is 3`。 ## map 是引用类型 @@ -382,11 +382,11 @@ func main() { 上面的程序将会报错:`invalid operation: map1 == map2 (map can only be compared to nil)`。 -比较两个 map 是否相等的方式是一一比较它们的元素是否相等。希望你能自己探索并编写一个达成这一功能的程序:) +比较两个 map 是否相等的方式是一一比较它们的元素是否相等。希望你能自己探索并编写一个达成这一功能的程序 :) 我(原文作者)已经将我们讨论的所有概念汇总到一个程序中,你可以从 [github](https://github.com/golangbot/arraysandslices) 下载。 -希望你喜欢阅读。请留下宝贵的意见和反馈:) +希望你喜欢阅读。请留下宝贵的意见和反馈 :) ## 以下为扩展知识 From fe48e6de52921cc37b396e78a7e75e0415c922e9 Mon Sep 17 00:00:00 2001 From: RickyWang1020 <50431019+RickyWang1020@users.noreply.github.com> Date: Wed, 26 Aug 2020 15:42:27 +0800 Subject: [PATCH 4/4] Update golang_tutorial_14.md --- docs/golang_tutorial_14.md | 41 +++++++++++++++++++++++++------------- 1 file changed, 27 insertions(+), 14 deletions(-) diff --git a/docs/golang_tutorial_14.md b/docs/golang_tutorial_14.md index 6f85b9a..34c809d 100644 --- a/docs/golang_tutorial_14.md +++ b/docs/golang_tutorial_14.md @@ -2,8 +2,8 @@ 14 - 字符串 ======================== -上一节:[第十篇 if else 语句](/docs/golang_tutorial_10.md) -下一节:[第十二篇 包](/docs/golang_tutorial_12.md) +上一节:[第十三篇 Map](/docs/golang_tutorial_13.md) +下一节:[第十五篇 指针](/docs/golang_tutorial_15.md) 这是本Golang系列教程的第14篇。 @@ -32,7 +32,9 @@ func main() { printBytes(name) } ``` -在上面的程序中,`len(s)` 返回字符串中的字节数,我们用一个 `for` 循环以 16 进制打印这些字节。`%x` 格式化指示符用来以 16 进制打印参数。上面的程序打印:`48 65 6c 6c 6f 20 57 6f 72 6c 64`。它们是 `"Hello World"` 以`UTF-8`方式编码的`Unicode`值。对 `Unicode` 字符集和 `UTF-8` 编码有一个基本的了解会更好的理解 `string` 类型。我(原文作者)建议大家阅读:https://naveenr.net/unicode-character-set-and-utf-8-utf-16-utf-32-encoding/ 来学习什么是 `Unicode` 和 `UTF-8`。 +在上面的程序中,`len(s)` 返回字符串中的字节数,我们用一个 `for` 循环以 16 进制打印这些字节。`%x` 格式化指示符用来以 16 进制打印参数。上面的程序打印:`48 65 6c 6c 6f 20 57 6f 72 6c 64`。它们是 `"Hello World"` 以 `UTF-8` 方式编码的 `Unicode` 值。对 `Unicode` 字符集和 `UTF-8` 编码有一个基本的了解会更好的理解 `string` 类型。我(原文作者)建议大家阅读:https://naveenr.net/unicode-character-set-and-utf-8-utf-16-utf-32-encoding/ 来学习什么是 `Unicode` 和 `UTF-8`。 + +## 访问字符串中的字符 让我们修改上面的程序以打印字符串中的字符: @@ -63,6 +65,7 @@ func main() { printChars(name) } ``` + 在第 16 行的 `printChars` 函数中,`%c` 格式化指示符用来打印字符串中的字符。上面的程序输出为: ```golang @@ -103,7 +106,9 @@ func main() { printChars(name) } ``` + 上面程序的输出为: + ```golang 48 65 6c 6c 6f 20 57 6f 72 6c 64 Hello World @@ -111,6 +116,8 @@ Hello World Señor ``` +我们尝试将 `"Señor"` 中的每个字符打印出来,但是却得到了 `"Señor"`。为什么这个程序在 `"Hello World"` 上运行正常,但是不适用于 `"Señor"` 呢?因为 `ñ` 的 `Unicode` 码点是 `U+00F1`,因而它的 `UTF-8` 编码占了两个字节:`c3` 和 `b1`。上面的程序假定每个码点只有一个字节长度,因此会发生错误。**在 `UTF-8` 编码中,一个码点可能会占一个以上的字节。**在这种情况下,我们需要 `rune` 来帮助解决问题。 + ## rune `rune` 是 Go 中的内置类型,它是 `int32` 的别名。在 Go 中,`rune` 表示一个 `Unicode` 码点。无论一个码点会被编码为多少个字节,它都可以表示为一个 `rune`。让我们修改上面的程序,使用 `rune` 来打印字符串中的字符。 @@ -148,7 +155,7 @@ func main() { } ``` -在上面的程序中,第 14 行,字符串被转换为 `tune` 切片。然后我们遍历该切片并打印其中的字符。程序的输出如下: +在上面的程序中,第 14 行,字符串被转换为 `rune` 切片。然后我们遍历该切片并打印其中的字符。程序的输出如下: ```golang 48 65 6c 6c 6f 20 57 6f 72 6c 64 @@ -156,11 +163,12 @@ Hello World 53 65 c3 b1 6f 72 Señor ``` -上面的输出是正确的。这正是我们想要的结果。 -## 使用 range for 遍历字符串 +上面的输出是正确的,这正是我们想要的结果。 + +## 使用 for range 遍历字符串 -上面的程序是遍历字符串中字符的一个正确方式。但是 Go 提供了一种更简单的方式来做到这一点:使用 `range` `for`。 +上面的程序是遍历字符串中字符的一个正确方式。但是 Go 提供了一种更简单的方式来做到这一点:使用 `for range` 循环。 ```golang package main @@ -181,7 +189,7 @@ func main() { } ``` -在上面的程序中,第 8 行通过使用 `range for` 遍历字符串。`range` 返回一个 `rune` (在 `byte` 数组中)的位置,以及 `rune` 本身。上面的程序输出为: +在上面的程序中,第 8 行通过使用 `for range` 循环遍历字符串。该循环返回一个 `rune` (在 `byte` 数组中)的位置,以及 `rune` 本身。上面的程序输出为: ```golang S starts at byte 0 @@ -191,7 +199,7 @@ o starts at byte 4 r starts at byte 5 ``` -从上面的输出可以看到,ñ 占两个字节:) +从上面的输出可以看到,ñ 占两个字节 :) ## 通过 `byte` 切片创建字符串 @@ -208,6 +216,7 @@ func main() { fmt.Println(str) } ``` + 在上面的程序中,`byteSlice` 是 `"Café"` 经过 `UTF-8` 编码后得到的切片(用 16 进制表示) 。上面的程序输出为:`Café`。 如果我们换成对应的十进制数程序会正常工作吗?答案是:`Yes`。让我们测试一下: @@ -225,9 +234,11 @@ func main() { fmt.Println(str) } ``` + 上面的程序同样输出:`Café`。 -## 通过 rune 切片创建字符串 +## 通过 `rune` 切片创建字符串 + ```golang package main @@ -241,12 +252,14 @@ func main() { fmt.Println(str) } ``` + 在上面的程序中,`runeSlice` 包含了字符串 `"Señor"` 的 `Unicode` 码点(以 16 进制表示)。程序的输出为:`Señor`。 -## 字符串的长度 +## 字符串的长度 + utf8 包 提供了 `func RuneCountInString(s string) (n int)` 来获取字符串的长度,该方法接受一个字符串作为参数,并返回该字符串中 `rune` 的数量。 -(译者注: `RuneCountInString` 返回字符串中 `Unicode` 字符的个数,而 `len` 返回字符串中 `byte` 的个数,注意两者的区别。 ) +(译者注:`RuneCountInString` 返回字符串中 `Unicode` 字符的个数,而 `len` 返回字符串中 `byte` 的个数。因此用 `len` 来获取字符串长度可能会导致错误。) ```golang package main @@ -296,7 +309,7 @@ func main() { } ``` -上面的程序中,第 8 行我们试图改变字符串的第一个字符为 `a`。因为字符串是不可变的,因此这是非法的,将会报错:`main.go:8: cannot assign to s[0]`。 +上面的程序中,第 8 行我们试图改变字符串的第一个字符为 `a`。任何在单引号内的 `Unicode` 字符都是 `rune`。由于字符串是不可变的,因此这是非法的,将会报错:`main.go:8: cannot assign to s[0]`。 **为了改变一个字符串中的字符,我们需要先把字符串转换为 `rune` 切片,然后修改切片中的内容,最后将这个切片转换回字符串**。 @@ -317,6 +330,6 @@ func main() { } ``` -在上面的程序中,第 7 行 `mutate` 函数接受一个 `rune` 切片作为参数。然后将该切片的第一个元素改为 `a`,最后再转换回字符串并返回。该函数在程序中的第 13 行被调用。`h` 被转换为一个 `rune` 切片传递给 `mutate`。程序的输出为:`aello`。 +在上面的程序中,第 7 行 `mutate` 函数接收一个 `rune` 切片作为参数。然后将该切片的第一个元素改为 `a`,最后再转换回字符串并返回。该函数在程序中的第 13 行被调用。`h` 被转换为一个 `rune` 切片传递给 `mutate`。程序的输出为:`aello`。 字符串的介绍到此为止。感谢阅读。