数组
定义
var
, :=
关键字; 元素数量写在类型前面
var arr1 [5] int // 中括号数字, 是指定元素个数, 默认元素为 0
arr2 := [3] int {1, 2, 3}
arr3 := [...] int {4, 5, 6, 7, 8} // 让编译器计算元素个数
var grid [4][5] int // 代表 4 行 5 列 二维数组, 只能用 var 声明
遍历
// 方式一
arr3 := [...] int {1, 3, 5, 7, 9}
for i := 0; i < len(arr3); i++ {
fmt.println(arr3[i])
}
// 方式二
for i := range arr3 {
fmt.Println(arr3[i])
}
// 方式三, 输出 i, v
for i, v := range arr3 {
fmt.println(i, v)
}
// 只输出 v, 使用 "_" 替换 i
for _, v := range arr3 {
fmt.println(v)
}
类型
-
数组是值类型
package main import "fmt" func printArray(arr [5]int) { // 若此处将数组下标为 0 的元素,会重新赋值成100 arr[0] = 100 for i, v := range arr { fmt.Println(i, v) } } func main() { var arr1 [5] int // 中括号数字, 是指定元素个数, 默认元素为 0 arr2 := [3] int {1, 2, 3} arr3 := [...] int {4, 5, 6, 7, 8} // 让编译器计算元素个数 var grid [4][5] int // 二维数组, 只能用 var 声明 fmt.Println(arr1, arr2, arr3) // 这里输出的数组还是原来的数组, 没有改变 fmt.Println(grid) printArray(arr3) }
小结
[10] int
和[20] int
是不同的类型- 调用
func f(arr [10] int)
会重新 拷贝 一个数组 Go
语言中一般不直接使用数组
切片 slice
概念
Go 语言切片是对数组的抽象。可以理解成数组的 view
Go 数组的长度不可改变,在特定场景中这样的集合就不太适用,Go 中提供了一种灵活,功能强悍的内置类型切片("动态数组"),与数组相比切片的长度是不固定的,可以追加元素,在追加时可能使切片的容量增大。
操作
基操
package main
import "fmt"
// slice 不是值传递,可以看成 视图
func updateSlice(s []int) {
s[0] = 100
}
func main() {
arr := [...] int {0, 1, 2, 3, 4, 5, 6, 7}
fmt.Println("arr[2:6] = ", arr[2:6])
fmt.Println("arr[:6] = ", arr[:6])
s1 := arr[2:]
fmt.Println("s1 = ", s1)
s2 := arr[:]
fmt.Println("s2 = ", s2)
fmt.Println("After updateSlice(s1)")
updateSlice(s1)
fmt.Println(s1)
fmt.Println(arr)
fmt.Println("After updateSlice(s2)")
updateSlice(s2)
fmt.Println(s2)
fmt.Println(arr)
fmt.Println("Reslice")
fmt.Println(s2)
s2 = s2[:5]
fmt.Println(s2)
s2 = s2[2:]
fmt.Println(s2)
}
// 结果
arr[2:6] = [2 3 4 5]
arr[:6] = [0 1 2 3 4 5]
s1 = [2 3 4 5 6 7]
s2 = [0 1 2 3 4 5 6 7]
After updateSlice(s1)
[100 3 4 5 6 7]
[0 1 100 3 4 5 6 7]
After updateSlice(s2)
[100 1 100 3 4 5 6 7]
[100 1 100 3 4 5 6 7]
Reslice
[100 1 100 3 4 5 6 7]
[100 1 100 3 4]
[100 3 4]
扩展
arr := [...] int {0, 1, 2, 3, 4, 5, 6, 7}
s1 := arr[2:6]
s2 := s1[3:5]
问 :
-
s1 的值?
-
s2 的值?
s1 的值 [2 3 4 5] s2 的值 [5 6]
答 :
s1
从 arr
中取得新数组 [2, 3, 4, 5]
, 那么 s1
的下标分别是 0, 1, 2, 3
; 由于s1
是 arr
的 view, s1
和 arr
存在映射关系. arr
中的元素 6, 7
对应着 s1
不可见下标 4, 5
; s2
获取 s1
的 3,5
等同于获取 arr
中的 5, 7
; 左开右闭 原则, 所以 s2
的值就是 [5, 6]
-
知识点
-
slice
可以向后扩展, 不可以向前扩展 -
s[i]
不可以超越len(s)
, 向后扩展不可以超越底层数组cap(s)
-
添加元素
arr := [...] int {0, 1, 2, 3, 4, 5, 6, 7}
s1 := arr[2:6]
s2 := s1[3:5]
s3 := append(s2, 10)
s4 := append(s3, 11)
s5 := append(s4, 12)
问 : s3, s4, s5 的值为多少? arr的值又变成
结果 :
[2 3 4 5]
[5 6]
[5 6 10]
[5 6 10 11]
[5 6 10 11 12]
- 关键字
append
- 添加元素时如果超越
cap
, 系统会重新分配更大的底层数组 - 由于值传递关系, 必须接收
append
的返回值 s = append(s, val)
复杂操作
-
追加
append(s, v)
第一个参数是追加的slice
, 第二个是element
func main () { var s [] int // 空的 slice, 默认 0 填充 for i := 0; i < 100; i++ { s = append (s, 2 * i + 1) } }
-
设置指定长度的
slice
make([]int, 16, 32)
第一个参数创建类型, 第二个参数是长度, 第三个是分配的空间(可选)// 建立长度为 16 的 slice s2 := make([]int, 16) s3 := make([]int, 10, 32)
-
复制
slice
copy(s1, s2)
第一个参数是要复制的目标slice
,第二个参数是源slice
s1 := [] int {2, 3, 4, 5} s2 := make([]int, 16) copy(s2, s1) // 结果 [2 3 4 5 0 0 0 0 0 0 0 0 0 0 0 0], len = 16, cap = 16
-
删除一个元素
没有删除函数, 采取截取, 再拼接的方式实现删除
s2 = append(s2[:3] , s2[4:]...) // 结果 [2 3 4 0 0 0 0 0 0 0 0 0 0 0 0], len = 15, cap = 16
-
头部 Pop 一个元素
同样, 也是采取截取的方式
s2 = s2[1:] // 结果 [3 4 0 0 0 0 0 0 0 0 0 0 0 0], len = 14, cap = 15
-
尾部 Pop 一个元素
同样, 也是采取截取的方式
s2 = s2[:len(s2) - 1] // 结果 [3 4 0 0 0 0 0 0 0 0 0 0 0], len = 13, cap = 15
Map
定义
关键字 map[k]v
格式 :
map[K]V, map[K1]map[K2]V
示例
创建
// 示例 一
m := map[string] string {
"name" : "mouse",
"course" : "golang",
"site" : "imooc"
}
// 示例 二
m2 := make(map[string]int) // m2 == empty mpa
// 示例 三
var m3 map[string]int // m3 == nil
应用
-
循环输出
// 循环输出 map for k, v := range m { fmt.println(k, v) } // 结果, 可以出来 map 的 k 是无序的 site imooc quality good name mouse course golang Getting values
-
获取其中一个值
// 获取 map 其中一个值 courseName, ok := m["course"] fmt.println(courseName, ok) // 结果 golang true
-
若
k
不存在// 若获取的 k 不存在, 则返回 空 causeName, ok2 := m["cause"] fmt.println(causeName, ok2) // 结果 "" false // 改写 if causeName, ok2 := m["cause"]; ok { fmt.println(causeName) } else { fmt.println("key does no exist") } // 结果 key does not exist
-
删除一个值
delete()
, 第一个参数是map
, 第二个参数是要删除的key
name, ok := m["name"] fmt.println(name, ok) delete(m, "name") // 结果 map[course:golang quality:good site:imooc]
小结
- 创建:
make(map[string]int)
- 获取元素 :
map[key]
- 若
key
不存在时, 则取得Value
类型的初始值, 不会报错 - 使用
value, ok := m[key]
两个值来判断key
是否存在 - 使用
delete(m, key)
删除一个值 - 使用
range
遍历key
, 或者遍历key
,value
对 - 不能保证遍历顺序, 若需要顺序, 可以添加到
slice
再对slice
排序 - 使用
len
获得元素个数 map
使用哈希表, 必须可以比较相等- 除了
slice
,map
,func
的内建类型都可以作为key
strut
类型不包含上述字段, 也可以作为key
高级操作
例子 一
寻找最长不含有重复字符的子串
abcabcbb ---> abc
bbbbb ---> b
pwwkew ---> wke
对于每一个字母 x
-
lastOccurred[x] 不存在, 或者 < start, 无需操作
-
lastOccurred[x] >= start, 则更新 start
-
更新 lastOccurred[x], 更新 maxLength
func lengthOfNonRepeatingSubStr(s string) int { lastOccurred := make(map[byte]int) start := 0 maxLength := 0 for i, ch := range []byte(s){ lastI, ok := lastOccurred[ch] if ok && lastI >= start { start = lastI + 1 } if i - start + 1 > maxLength { maxLength = i - start + 1 } lastOccurred[ch] = i } return maxLength }
计算中文等汉字会出现问题
字符和字符串处理
rune
相当于 Go 的 char
package main
import (
"fmt"
"unicode/utf8"
)
func main() {
s := "Yes中文!"
fmt.println(s) // 输出结果: 10
for _, b := range []byte(s) {
fmt.printf("%X ", b) // 输出十六进制
}
}
// 引入 unicode/utf8 包
fmt.Println("Rune count", utf8.RuneCountInString(s)) // 输出6
bytes := []byte(s)
for len(bytes) > 0 {
ch, size := utf8.DecodeRune(bytes)
bytes = bytes[size:]
fmt.printf("%c ", ch) // 输出 Y e s 中 文 !
}
// 使用 rune, 可直接输出汉字
for i, ch := range []rune(s) {
fmt.printf("(%d, %c)", i, ch) // 输出 (0, Y)(1, e)(2, s)(3, 中)(4, 文)(5, !)
}
再对上面的例子 一, 遗留的问题进行修改
func lengthOfNonRepeatingSubStr(s string) int {
// 将 byte 修改成 rune 即可解决
lastOccurred := make(map[rune]int)
start := 0
maxLength := 0
// 将 byte 修改成 rune 即可解决
for i, ch := range []rune(s){
lastI, ok := lastOccurred[ch]
if ok && lastI >= start {
start = lastI + 1
}
if i - start + 1 > maxLength {
maxLength = i - start + 1
}
lastOccurred[ch] = i
}
return maxLength
}
-
其他字符操作
推荐使用
strings
package 来处理, 里面有很多函数, 多多尝试就会用了