指针类型
定义指针
var a int = 10
var p *int = &a
pp := &a
空指针
- 默认值,空指针的值为
nil。
访问指针
- 使用
*ptr访问值,地址无法访问将产生运行错误。 - 结构体使用
name.attr访问元素,在Golang中可以使用ptr.attr通过指针访问元素(Clang是ptr->attr)。
结构体类型
定义结构体
- 具名结构体
type Book struct {
name string
author string
}
var a Book // 定义默认结构体
var b = Book{"Golang 入门经典", "Unknown"} // 全部初始化
var c = Book{name: "C++ 入门指南"} // 局部初始化
d := Book{name: "鸟哥的 Linux 私房菜"} // 使用 :=
var e *Book = new(Book) // 使用指针
- 字段匿名
type Book struct {
string
string
}
var a Book = Book{"Golang 入门经典", "Unknown"}
- 结构体匿名
var a = struct{
name string
author string
}{"Golang 入门经典", "Unknown"}
- 两种匿名不可同时使用。
访问结构体
var a Book = Book{"Golang 入门经典", "Unknown"}
var p *Book = &a
fmt.Println(a.name, a.author)
fmt.Println(p.name, p.author) // 结构体指针直接使用 ptr.attr 访问
类型转换
- 如果两个结构体具有完全相同的定义,它们可以进行显式类型转换。
嵌套与继承
- 结构体嵌套将一个结构体作为新结构体的一个字段。
type Library struct {
name string
books []Book
}
- 结构体继承将一个结构体的字段和方法引入新结构体。结构体的方法后面会提及。
type ChildBook struct {
fitAge int
Book
}
数组类型
定义数组
var a [3]int
var b = [3]int{1, 2, 3}
var c = [...]int{1, 2, 3} // 注意 [...]int 是数组, []int 是切片 (下一节会讲)
d := [...]int{1, 2, 3}
传递数组
Golang中数组名表示整个数组。这与Clang表示数组头指针不同,但与其std::array类似。传递数组有时会产生很大的开销,可以使用指针数组。
var a [3]int = [3]int{1, 2, 3}
var p *[3]int = &a
切片类型
定义切片
var a []int // [], 注意 [3]int / [...]int 都是数组不是切片
var a = []int{1, 2, 3} // [1 2 3]
a := []int{1, 2, 3} // [1 2 3]
var a = make([]int, 3) // [0 0 0]
// make: make 只用于构造 slice / map / channel, 第一个参数为类型, 第二个参数为大小
切片原型
slice是引用数据类型,对切片的赋值不会拷贝数据,切片的切片也是引用而非拷贝。- 后面介绍的所有切片操作请注意区别 引用与拷贝
type SliceHeader struct {
Data uintptr // 数据存储地址
Len int // 数据长度
Cap int // 数据申请长度
}
切片操作
切片
-
切片是一种数据类型也是一种操作
-
进行切片的对象可以是数组或切片,将返回
SliceHeader,是对数据的引用而非拷贝。 -
Golang中的切片应与Python区分的是:Golang中索引不可使用负数表示,并且不可设置步长。
var a = []int{1, 2, 3}
b := a[:] // [1 2 3] 如果 a 是一个数组, 此方法将创建一个切片
c := a[1:] // [2 3]
c := a[:2] // [1 2]
c := a[1:2] // [2]
append() 与 copy()
append()与copy()都是对数据的拷贝,会对引用到的所有数据进行拷贝。
var a = []int{1, 2}
var b = []int{4, 5, 6}
var c []int = append(a, 4) // [1 2 4] 传入切片类型与元素类型, 返回切片类型
var d []int = append(a, 4, 5, 6) // [1 2 4 5 6] 传入切片类型与多个元素类型,返回切片类型
var e []int = append(a, b...) // [1 2 4 5 6] 传入两个切片类型, 返回切片类型, 是将 b 追加到 a 尾后的新切片
var i int = copy(a, b) // 2 [4 5] [4 5 6] 将 b 拷贝到 a , 返回拷贝量, 拷贝量为 min(len(a), len(b))
Golang中args...表示解包,对应Python中的*args。
常见组合操作
拷贝切片
b := append([]int{}, a...)
b := make([]int, len(a))
copy(b, a)
原地删除
- 原地删除首部
a = a[st:] // 删除前 st 个元素
- 原地删除尾部
a = a[:ed] // 保留前 ed 个元素
- 原地截取中部
a = a[st:ed] // 截取索引 [st, ed) 元素
- 原地删除中部
a = append(a[:st], a[ed:]...) // 删除索引 [st, ed) 元素
原地插入
- 原地末尾追加
a = append(a, b...)
- 原地首部插入
a = append(b, a...)
- 原地中间插入
a = append(append(a[:st], b...), a[st:]...) // 从第 st 个元素开始插入元素
字符串类型
定义字符串
- 在
Golang字符串默认使用UTF-8编码。
var a string = "Hello World!"
var b = "Golang 入门经典"
c := "abcABC123"
字符串原型
- 字符串是引用数据类型,底层使用
[...]byte存储,而使用UTF-8解析。与Java相似字符串作常量使用,不直接修改其值。
type StringHeader struct {
Data uintptr
Len int
}
字符串操作
- 许多字符串操作位于库文件
strings中,许多字符串类型转换位于库文件strconv中。 - 这里假设已经定义了两个变量:
var a = "你好"
var b = "Hello"
字符串切片
- 字符串可以认为是一个静态切片类型,可以进行相应的切片操作。不可使用
append和copy函数。
字符串拼接
c := a + b // 运算符 两字符串拼接
c = strings.Join([]string{a, b}, "") // 函数 多字符串拼接
// 官方推荐的 最高效率
var builder strings.Builder // 或 builder := strings.Builder{}
builder.WriteString(a)
builder.WriteString(b)
var s string = builder.String() // 或 s := builder.String()
字符串编码
c := []byte(a) // 转换为 ASCII 编码, 一个 Unicode 字符占用 3 Bytes
d := len(c) // 6
c := []rune(a) // 转换为 UTF-8 编码
d := len(c) // 2
- 对
string类型直接使用len(),返回值为ASCII编码长度。
其他操作
func strings.Contains(s string, substr string) bool // s 是否包含 substr
func strings.HasPrefix(s string, prefix string) bool // s 是否以 substr 开头
func strings.HasSuffix(s string, suffix string) bool // s 是否以 substr 结尾
func strings.Index(s string, substr string) int // substr 在 s 中第一次出现的索引
func strings.LastIndex(s string, substr string) int // substr 在 s 中最后次出现的索引
func strings.ToLower(s string) string // 返回 s 的小写形式
func strings.ToUpper(s string) string // 返回 s 的大写形式
func strings.EqualFold(s string, t string) bool // 不区分大小写的情况下, s 与 t 是否相等
func strings.Split(s string, sep string) []string // 以 sep 分割字符串 s
func strings.SplitN(s string, sep string, n int) []string
// 以 sep 分割字符串 s. 最多将字符串分割为 n 份, -1 表示无穷
func strings.SplitAfter(s string, sep string) []string // 以 sep 分割字符串 s, sep 会保留在前一个字符串尾
func strings.SplitAfterN(s string, sep string, n int) []string
// 以 sep 分割字符串 s, sep 会保留在前一个字符串尾. 最多将字符串分割为 n 份, -1 表示无穷
// ??? 为什么 go 没有 rsplit
func strings.Join(elem []string, sep string) string // 以 sep 衔接 elem 中元素, Split 的逆过程
func strings.Replace(s string, old string, new string, n int) string
// 将 s 中的 old 替换为 new 至多 n 次, n 为 -1 表示无穷
func strings.ReplaceAll(s string, old string, new string) string // 替换全部
func string.Repeat(s string, n int) string // s 重复 n 次
func strings.TrimSpace(s string) string // 去除前后空字符
func strings.Trim(s string, chars string) string // 去除前后 chars 中的字符
func strings.TrimLeft(s string, chars string) string // 去除前导 chars 中的字符
func strings.TrimRight(s string, chars string) string // 去除后导 chars 中的字符
func strings.TrimPrerix(s string, prefix string) string // 去除前导 prefix 字符串至多一次
// func strings.CutPrefix(s string, prefix string) (string, bool) // 功能相似, 返回是否去除
func strings.TrimSuffix(s string, suffix string) string // 去除后导 suffix 字符串至多一次
// func strings.CutSuffix(s string, suffix string) (string, bool) // 功能相似, 返回是否去除
字符串转换
转换为字符串类型
func fmt.Sprint(a ...any) string // 将任意类型转换为字符串, 只要类型满足 fmt.Stringer 接口
// fmt.Sprint(Complex(1, 5))
转换自字符串类型
func strconv.ParseBool(s string) (bool, error)
// 将 string 转为 bool 类型 (true/false), 如果错误存在同时返回
func strconv.ParseComplex(s string, bitSize int) (complex128, error)
// 将 string 转为 complex 类型, 如果错误存在同时返回
// bitSize 为 64/128 表示 complex64/complex128, 一般使用 128
func strconv.ParseFloat(s string, bitSize int) (float64, error)
// 将 string 转为 complex 类型, 如果错误存在同时返回
// bitSize 为 32/64 表示 float32/float64, 一般使用 64
func strconv.ParseInt(s string, base int, bitSize int) (int64, error)
// 将 string 转为 complex 类型, 如果错误存在同时返回
// base 为进制 0/2-36, 特别地, 0 表示自动进制
// 0b 开头被识别为二进制
// 0o 开头被识别为八进制
// 0x 开头被识别为十六进制
// 否则被识别为十进制
// bitSize 为 8/16/32/64 表示 int8/int16/int32/int64, 一般使用 64
func strconv.ParseUint(s string, base int, bitSize int) (uint64, error) // 与 strconv.ParseInt 相似