Golang
2020-12-19
https://github.com/moovweb/gvm
安装
bash < <(curl -s -S -L https://raw.githubusercontent.com/moovweb/gvm/master/binscripts/gvm-installer)
使用
source ~/.gvm/scripts/gvm
gvm listall
# gvm 默认从 github 克隆代码到本地,然后进行编译
# 可以采用 gitee 仓库加速
git clone git@gitee.com:mirrors/go ~/.gvm/archive/go
gvm install go1.16
gvm list
gvm use go1.16
go version
# go version go1.16 linux/amd64
Golang
2020-12-18
package main
import (
"encoding/json"
"fmt"
"reflect"
)
type Address struct {
City string `json:"city"`
Country string `json:"country"`
}
type User struct {
Username string `json:"username"`
Password string `json:"password"`
}
type Person struct {
Name string `json:"name"`
Age int `json:"age"`
Address Address `json:"address"`
// 这么写,JSON 会多一层
// User `json:"user"`
User
}
func (p Person) SayHello() {
fmt.Println("Hello, my name is", p.Name)
}
func main() {
person := Person{
Name: "Bob",
Age: 30,
Address: Address{
City: "London",
Country: "UK",
},
User: User{
Username: "bob1999",
Password: "pa55w0rd",
},
}
// 属性操作
fmt.Println("Name:", person.Name)
fmt.Println("Age:", person.Age)
fmt.Println("City:", person.Address.City)
fmt.Println("Country:", person.Address.Country)
fmt.Println("Username:", person.Username)
fmt.Println("Password:", person.Password)
fmt.Printf("%+v\n", person)
fmt.Printf("%#v\n", person)
// 方法调用
person.SayHello()
// 通过反射获取标签内容
t := reflect.TypeOf(person)
for i := 0; i < t.NumField(); i++ {
field := t.Field(i)
tag := field.Tag.Get("json")
fmt.Println(field.Name, ":", tag)
}
// JSON 序列化
jsonData, err := json.Marshal(person)
if err != nil {
fmt.Println(err)
}
fmt.Println("JSON:", string(jsonData))
}
// Name: Bob
// Age: 30
// City: London
// Country: UK
// Username: bob1999
// Password: pa55w0rd
// main.Person{name:"Bob", age:30, address:main.Address{city:"London", country:"UK"}, User:main.User{username:"bob1999", password:"pa55w0rd"}}
其他知识点:
-
字段名大小写问题:首字母小写的话,只有本包可以访问
-
Zero-value Struct
type Fruit struct {
name string
}
var apple Fruit
fmt.Println(apple) // {}
- new 关键字
package main
import "fmt"
type Employee struct {
Name string
Age int
}
func main() {
p := new(Employee)
fmt.Println(p) // &{ 0}
var p2 Employee
fmt.Println(p2) // { 0}
p3 := Employee{"Me", 30}
fmt.Println(p3) // {Me 30}
}
- struct 字面量
type Person struct {
Name string
Age int
Email string
}
p1 := Person{
Name: "Alice",
Age: 25,
Email: "alice@example.com",
}
p2 := Person {"Alice", 25, "alice@example.com"}
-
指针
-
匿名结构体
package main
import (
"fmt"
)
func main() {
user := struct {
username string
}{
username: "admin",
}
fmt.Printf("%+v\n", user)
// {username:admin}
fmt.Printf("%#v\n", user)
// struct { username string }{username:"admin"}
fmt.Printf("%v\n", user)
// {admin}
fmt.Println(user)
// {admin}
}
场景:
- 定义一个临时结构体接收反序列化数据
-
内嵌结构体
-
匿名属性(或者应该叫啥,我也不知道)
-
内嵌类型不能重复,
- 前面的例子可以看出,可以直接访问匿名属性(结构体)内部属性,
- 但是如果同名就只能老老实实通过类型名字来访问了
package main
import (
"fmt"
)
type Book struct {
string // book name (anno field)
// syntax error: unexpected [, expected field name or embedded type
// []Author
Authors []Author // slice of authors
Publisher
}
type Author struct {
string // author name (anno field)
}
type Publisher struct {
string // publisher name (anno field)
}
func main() {
p := Book{
string: "Learning Python",
Authors: []Author{
{string: "Stanley B.Lippman"},
{string: "Josée LaJoie"},
{"Barbara E.Moo"},
},
Publisher: Publisher{"人民邮电出版社"},
}
p.string = "C++ Primer" // change attr
fmt.Println(p)
fmt.Printf("%v\n", p)
fmt.Printf("%+v\n", p)
fmt.Printf("%#v\n", p)
fmt.Printf("%v\n", p.string)
fmt.Printf("%v\n", p.Authors[0].string)
fmt.Printf("%v\n", p.Publisher)
fmt.Printf("%v\n", p.Publisher.string)
}
// {C++ Primer [{Stanley B.Lippman} {Josée LaJoie} {Barbara E.Moo}] {人民邮电出版社}}
// {C++ Primer [{Stanley B.Lippman} {Josée LaJoie} {Barbara E.Moo}] {人民邮电出版社}}
// {string:C++ Primer Authors:[{string:Stanley B.Lippman} {string:Josée LaJoie} {string:Barbara E.Moo}] Publisher:{string:人民邮电出版社}}
// main.Book{string:"C++ Primer", Authors:[]main.Author{main.Author{string:"Stanley B.Lippman"}, main.Author{string:"Josée LaJoie"}, main.Author{string:"Barbara E.Moo"}}, Publisher:main.Publisher{string:"人民邮电出版社"}}
// C++ Primer
// Stanley B.Lippman
// {人民邮电出版社}
// 人民邮电出版社
- 将函数通过属性的方式定义
type FoodNameGetter func(string) string
type Food struct {
name string
getter FoodNameGetter // declare function
}
pizza := Food{
name: "Pizza",
getter: func(name string) string { // declare function body
return "This is " + name + "."
},
}
- 结构体比较
如果类型和值相同,就等于。
package main
import "fmt"
type Teacher struct {
name string
}
type Student struct {
name string
}
func main() {
s1 := Student{"John"}
s2 := Student{"John"}
fmt.Println(s1 == s2) // true
// invalid operation: s1 == t1 (mismatched types Student and Teacher)
// t1 := Teacher{"John"}
// fmt.Println(s1 == t1)
}
参考资料与拓展阅读
Golang
2020-12-18
点后直接括号
- type assertion 类型断言
- type switch 类型判断
Golang 是强类型的语言,这两种语法都是只对 interface{}
有效。
package main
import "fmt"
func test(value interface{}) {
switch value.(type) {
case string:
fmt.Printf("%#v\n", value)
}
}
func test2(value interface{}) {
v1, ok := value.([]byte)
fmt.Printf("%#v, %#v\n", v1, ok)
v2, ok := value.(string)
fmt.Printf("%#v, %#v\n", v2, ok)
}
func main() {
a := "abc"
test(a)
test2(a)
}
Golang
2020-12-15
声明
# array
[length]Type
[length]Type{v1, v2, ..., vn}
[...]Type{v1, v2, ..., vn}
# slice
[]Type
[]Type{v1, v2, ..., vn}
make([]Type, length)
make([]Type, length, capacity)
我想尝试动态创建数组(通过 arrLen 变量),没有找到方法,可能这就是静态类型语言吧。
所以,数组必须在写代码的时候就明确长度。否则就应该用切片。
此外,数组应该算是值类型。赋值的时候,会完全复制一份,传参也是一样。
Slice 等于数组指针 + 长度 + 容量。
package main
import "fmt"
func main() {
var a []int
fmt.Printf("%#v \t%d %d\n", a, len(a), cap(a)) // []int(nil) 0 0
b := []int{1, 2, 3}
fmt.Printf("%#v \t%d %d\n", b, len(b), cap(b)) // []int{1, 2, 3} 3 3
var c [3]int
fmt.Printf("%#v \t%d %d\n", c, len(c), cap(c)) // [3]int{0, 0, 0} 3 3
d := [...]int{1, 2, 3}
fmt.Printf("%#v \t%d %d\n", d, len(d), cap(d)) // [3]int{1, 2, 3} 3 3
d2 := [...]int{3: 100}
fmt.Printf("%#v \t%d %d\n", d2, len(d2), cap(d2)) // [4]int{0, 0, 0, 100} 4 4
e := d[:]
fmt.Printf("%#v \t%d %d\n", e, len(e), cap(e)) // []int{1, 2, 3} 3 3
// 动态创建切片
f := make([]int, 3, 10)
fmt.Printf("%#v \t%d %d\n", f, len(f), cap(f)) // []int{0, 0, 0} 3 10
// new 返回指针
g := new([]int)
fmt.Printf("%#v \t%d %d\n", g, len(*g), cap(*g)) // &[]int(nil) 0 0
h := new([3]int)
fmt.Printf("%#v \t%d %d\n", h, len(*h), cap(*h)) // &[]int{0, 0, 0} 3 3
type User struct {
Username string
Password string
}
users := []User{
{"a", "pass1"},
{"b", "pass2"}, // 这样分行写的话,不能省略这个逗号
}
fmt.Printf("%+v \t%d %d\n", users, len(users), cap(users))
// [{Username:a Password:pass1} {Username:b Password:pass2}] 2 2
}
索引
a[n]
a[n:m]
a[n:]
a[:m]
a[:]
// 索引为负数
// invalid argument: index -1 (constant of type int) must not be negative
// 索引越界
// invalid argument: array index 10 out of bounds [0:5]
遍历
for i := 0; i < len(arr); i++ {
val := arr[i]
// ...
}
for i, val := range arrayVar {
// ...
}
// 如果只有一个变量接收遍历的值,那么这个变量将是 index
// 这个地方总是容易写错,要小心
for i := range arrayVar {
val := arrayVar[i]
// ...
}
复制
s1 := []int{1, 3, 6}
s2 := append([]int{}, s1...)
fmt.Printf("%#v %p\n", s1, s1)
fmt.Printf("%#v %p\n", s2, s2)
s3 := make([]int, len(s1))
copy(s3, s1)
fmt.Printf("%#v %p\n", s3, s3)
注意:copy 复制内容的长度以 src,dst 中较小的长度为准。
删除
a := []int{1, 2, 3, 4, 5, 6, 7}
// del a[3]
a = append(a[:3], a[4:]...)
插入
// 在尾部插入一个
a = append(a, ele)
// 在尾部插入一个数组或切片
a = append(a, arr...)
// copy 也是一种方法
a := [10]int{1, 2, 3}
b := []int{4, 5, 6}
copy(a[3:], b)
// WRONG!
a := []int{1, 2, 3, 5, 6, 7}
tmp := a[:3]
tmp = append(tmp, 4)
fmt.Println(a) // [1 2 3 4 6 7]
func insert(slice []int, index int, num int) []int {
rest_len := len(slice) - index
tmp := make([]int, rest_len, len(slice)+1)
copy(tmp, slice[:index])
tmp[index] = num
tmp = append(tmp, slice[index:]...)
return tmp
}
弹出
数组长度固定无法执行“弹出”操作,但是可以删除其中的一个节点。
nums := []int{1, 2, 3, 4}
first := nums[0]
nums = nums[1:]
last := nums[len(nums) - 1]
nums := nums[:len(nums) - 1]
合并
package main
import "fmt"
func main() {
a := []int{1, 2, 3}
b := []int{1, 2, 3}
c := [3]int{4, 5, 6}
d := [3]int{4, 5, 6}
// 切片合并
e := append(a, b...)
fmt.Printf("%#v, %#v, %#v\n", a, b, e)
f := append(c[:], d[:]...)
fmt.Printf("%#v, %#v, %#v\n", c, d, f)
g := [6]int{}
for i, v := range a {
g[i] = v
}
length := len(a)
for i, v := range a {
g[i+length] = v
}
fmt.Printf("%#v\n", g)
h := [6]int{}
// func copy(dst, src []Type) int
copy(h[:], a)
fmt.Printf("%#v\n", h)
copy(h[3:], a)
fmt.Printf("%#v\n", h)
}
排序
package main
import (
"fmt"
"sort"
)
func main() {
nums := []int{9, 5, 2, 7, 1}
sort.Ints(nums)
fmt.Println(nums)
}
- sort.Strings
- sort.Float64s
Golang
2020-12-11
godoc -http=:6060 -index -play -timestamps -v
# 如果在 go 模块目录执行,会列出本地依赖包的文档
# using module mode; GOMOD=xxx.mod
go doc fmt
go doc fmt.Println
go doc fmt Println
go doc -src fmt Println
# 查看本地包文档
go doc github.com/astaxie/beego
go doc github.com/astaxie/beego Listen
go doc -all github.com/astaxie/bee
PS: 关于 Go 项目文档
- 紧挨者
package
, const
, type
, func
等关键字的注释
问题
C:\Users\admin>godoc -http=:6060 -index -play -timestamps -v
'godoc' 不是内部或外部命令,也不是可运行的程序
或批处理文件。
新版本不再自带 godoc 工具,需要另外安装:
go install golang.org/x/tools/cmd/godoc@latest
Golang
2020-12-09
- 算术运算符 Arithmetic Operators
+
-
*
/
%
++
--
- 比较运算符 Comparison Operators
>
<
==
!=
>=
<=
- 逻辑运算符 Logical Operators
&&
||
!
- 按位运算符 Bitwise Operators
&
按位与 bitwise AND
|
按位或 bitwise OR
^
按位取反 bitwise NOT / 按位异或 bitwise XOR
- 注意:其他很多语言都是采用
~
表示取反
&^
bit clear (AND NOT)
<<
左移,>>
右移
- 赋值运算符 Assignment Operators
=
以及算术运算赋值,位运算赋值
- 其他运算符 Misc Operators
*
指针,&
取地址,<-
通道接收
Operator precedence
| 优先级 | 运算符 |
| ------ | ------------------------------ | ----- | --- |
| 5 | *
/
%
<<
>>
&
&^
|
| 4 | +
-
|
^
|
| 3 | 关系运算符 |
| 2 | &&
|
| 1 | | |
|
示例
package main
import "fmt"
func main() {
var a uint8 = 0b_0011_1100 // 60
var b uint8 = 0b_0000_1111 // 15
fmt.Printf(" a %08b (%d)\n", a, a)
fmt.Printf(" b %08b (%d)\n", b, b)
fmt.Println()
fmt.Printf(" NOT %08b 非(NOT a)\n", (^a))
fmt.Println()
fmt.Printf(" AND %08b 与\n", (a & b))
fmt.Printf(" OR %08b 或\n", (a | b))
fmt.Printf(" XOR %08b 异或\n", (a ^ b))
fmt.Println()
fmt.Printf(" NAND %08b 与非\n", ^(a & b))
fmt.Printf(" NOR %08b 或非\n", ^(a | b))
fmt.Printf(" XNOR %08b 同或(异或非)\n", ^(a ^ b))
fmt.Println()
fmt.Printf("AND NOT %08b BitClear\n", (a &^ b))
// fmt.Printf("AND NOT %08b BitClear\n", (a & (^b)))
// 格式化工具会将 ^ 和右操作数放在一起
// 这一点和 &^ 不同,应该是由于 Golang Spec 中,将 &^ 当成一个操作符
// 本质上,没有什么区别,都是先按位取反,再按位与或
fmt.Printf(" OR NOT %08b Useless\n", (a | ^b))
// fmt.Printf(" OR NOT %08b Useless\n", (a | (^b)))
}
// a 00111100 (60)
// b 00001111 (15)
// NOT 11000011 非(NOT a)
// AND 00001100 与
// OR 00111111 或
// XOR 00110011 异或
// NAND 11110011 与非
// NOR 11000000 或非
// XNOR 11001100 同或(异或非)
// AND NOT 00110000 BitClear
// OR NOT 11111100 Useless
参考资料与拓展阅读
Golang
2020-12-08
https://github.com/golang/go/blob/master/src/strings/builder.go
主要的作用是频繁拼接字符串,相比字符串拼接操作符(+
)或者 fmt.SPrintf
效率更高。
实例
package main
import (
"fmt"
"strings"
)
func main() {
var builder strings.Builder
builder.WriteString("Hello")
builder.WriteString(", ")
builder.WriteString("World!")
result := builder.String()
fmt.Println(result)
}
方法
func (b *Builder) String() string
func (b *Builder) Len() int { return len(b.buf)
func (b *Builder) Cap() int { return cap(b.buf)
func (b *Builder) Reset()
内容重置
func (b *Builder) Grow(n int)
预分配空间,正确使用可以提升程序执行效率
func (b *Builder) Write(p []byte) (int, error)
func (b *Builder) WriteByte(c byte) error
func (b *Builder) WriteRune(r rune) (int, error)
func (b *Builder) WriteString(s string) (int, error)
源码
实际上就是针对 []byte
的一个封装。
// A Builder is used to efficiently build a string using Write methods.
// It minimizes memory copying. The zero value is ready to use.
// Do not copy a non-zero Builder.
type Builder struct {
addr *Builder // of receiver, to detect copies by value
buf []byte
}
func (b *Builder) copyCheck() {
if b.addr == nil {
// This hack works around a failing of Go's escape analysis
// that was causing b to escape and be heap allocated.
// See issue 23382.
// TODO: once issue 7921 is fixed, this should be reverted to
// just "b.addr = b".
b.addr = (*Builder)(noescape(unsafe.Pointer(b)))
} else if b.addr != b {
panic("strings: illegal use of non-zero Builder copied by value")
}
}
// WriteString appends the contents of s to b's buffer.
// It returns the length of s and a nil error.
func (b *Builder) WriteString(s string) (int, error) {
b.copyCheck()
b.buf = append(b.buf, s...)
return len(s), nil
}
addr
指向自己的指针,不知道干什么用
buf
是 buffer,缓冲区,用于存储 build 出来的字符串
- 通过缓冲区做存储,避免频繁创建字符串对象,减少内存分配和垃圾回收
性能测试
BenchmarkStrPlus-20 100000000 11.11 ns/op 0 B/op 0 allocs/op
BenchmarkSprintf-20 12129922 101.5 ns/op 48 B/op 3 allocs/op
BenchmarkStrJoin-20 45257742 24.47 ns/op 16 B/op 1 allocs/op
BenchmarkStrBuilder-20 38868284 36.31 ns/op 24 B/op 2 allocs/op
BenchmarkByteBuf-20 22016934 53.34 ns/op 80 B/op 2 allocs/op
BenchmarkByteSlice-20 31495318 36.13 ns/op 24 B/op 2 allocs/op
BenchmarkByteSlice2-20 39563612 32.18 ns/op 24 B/op 2 allocs/op
BenchmarkStrPlusBatch-20 7331364 170.0 ns/op 112 B/op 6 allocs/op
BenchmarkSprintfBatch-20 1481492 823.2 ns/op 328 B/op 20 allocs/op
BenchmarkStrJoinBatch-20 19598844 59.78 ns/op 32 B/op 1 allocs/op
BenchmarkStrBuilderBatch-20 13560961 87.39 ns/op 56 B/op 3 allocs/op
BenchmarkByteBufBatch-20 10693280 97.61 ns/op 96 B/op 2 allocs/op
BenchmarkByteSliceBatch-20 12115166 95.27 ns/op 56 B/op 3 allocs/op
BenchmarkByteSlice2Batch-20 13136418 90.53 ns/op 56 B/op 3 allocs/op
fmt.Sprintf 用来做字符串拼接的话,性能总是最差。
此外,如果只是简单的两个字符串相加,直接加号拼接性能最好。
否则就根据情况,选用其他方案比较好。
Golang
2020-12-08
byte
实际上是 uint8
的别名,[]byte
也就是 uint8
切片。
常见操作
package main
import (
"bytes"
"encoding/hex"
"fmt"
"strconv"
)
func main() {
// 1. 转换
str1 := "HELLO WORLD"
bytes0 := []byte(str1) // string to bytes
str2 := string(bytes0) // bytes to string
fmt.Printf("%#v\n", bytes0)
// []byte{0x48, 0x45, 0x4c, 0x4c, 0x4f, 0x20, 0x57, 0x4f, 0x52, 0x4c, 0x44}
fmt.Println(str1, bytes0, str2)
// HELLO WORLD [72 69 76 76 79 32 87 79 82 76 68] HELLO WORLD
// 2. 连接
bytes1 := []byte("HELLO ")
bytes2 := []byte("WORLD")
bytes3 := append(bytes1, bytes2...)
fmt.Println(bytes3)
// [72 69 76 76 79 32 87 79 82 76 68]
// 3. 拷贝
bytes4 := make([]byte, len(bytes3))
copy(bytes4, bytes3)
fmt.Println(bytes4)
// [72 69 76 76 79 32 87 79 82 76 68]
// 4. 长度和容量
fmt.Println(len(bytes4), cap(bytes4)) // 11 11
// 5. 截取
bytes5 := bytes4[7:10]
fmt.Println(bytes5) // [79 82 76]
// 6. 比较
bytes6 := []byte("HELLO WORLD")
fmt.Println(bytes.Equal(bytes4, bytes6)) // true
// 7. 遍历
for i := 0; i < len(bytes6); i++ {
fmt.Printf("%d ", bytes6[i])
}
fmt.Println()
// 72 69 76 76 79 32 87 79 82 76 68
// 8. 转化为数字
bytes7 := []byte("12345")
num, _ := strconv.Atoi(string(bytes7))
fmt.Println(num) // 12345
// 9. 转化为16进制字符串
bytes8 := []byte("HELLO WORLD")
hexStr := hex.EncodeToString(bytes8)
fmt.Println(hexStr) // 48454c4c4f20574f524c44
}
输出
package main
import (
"bytes"
"fmt"
"io"
"os"
)
func main() {
buf := new(bytes.Buffer) // *bytes.Buffer
// func (b *Buffer) WriteString(s string) (n int, err error)
buf.WriteString("HELLO ")
buf.WriteString("WORLD")
fmt.Println(string(buf.Bytes()))
fmt.Println(buf.String()) // 相同
// ========================================
w := os.Stdout // *os.File
// func (f *File) Write(b []byte) (n int, err error)
// func (f *File) WriteString(s string) (n int, err error)
w.WriteString("HELLO ")
n, err := io.WriteString(w, "WORLD\n")
if err != nil {
panic(err)
}
fmt.Printf("n: %d\n", n)
}
利用 reflect 实现 bytes / string 转换
参考:https://www.sobyte.net/post/2022-01/go-string-bytes/
func String2Bytes(s string) []byte {
sh := (*reflect.StringHeader)(unsafe.Pointer(&s))
bh := reflect.SliceHeader{
Data: sh.Data,
Len: sh.Len,
Cap: sh.Len,
}
return *(*[]byte)(unsafe.Pointer(&bh))
}
func Bytes2String(b []byte) string {
return *(*string)(unsafe.Pointer(&b))
}
Golang
2020-12-08
package main
func main() {
a := "hello 世界"
fmt.Printf("%#v (%d)\n", a, len(a))
// "hello 世界" (12)
// 按 rune ForRange 循环
for k, v := range a {
fmt.Printf("%#4v. %#6v (%T)\n", k, v, v)
}
// 按 byte 索引取值
fmt.Printf("a[0]: %#6v (%T)\n", a[0], a[0])
fmt.Printf("a[6]: %#6v (%T)\n", a[6], a[6])
// 0. 104 (int32)
// 1. 101 (int32)
// 2. 108 (int32)
// 3. 108 (int32)
// 4. 111 (int32)
// 5. 32 (int32)
// 6. 19990 (int32)
// 9. 30028 (int32)
// a[0]: 0x68 (uint8)
// a[6]: 0xe4 (uint8)
b := []byte(a)
fmt.Printf("%#v\n", b)
// []byte{0x68, 0x65, 0x6c, 0x6c, 0x6f, 0x20, 0xe4, 0xb8, 0x96, 0xe7, 0x95, 0x8c}
c := []rune(a)
fmt.Printf("%#v\n", c)
// []int32{104, 101, 108, 108, 111, 32, 19990, 30028}
}
len(s)
strings.Join(s1, s2) string
连接字符串
strings.ContainsRune(s, rune) bool
strings.Contains(s, substr) bool
子串包含判断
注意:任何字符串都包含空字符串
strings.ContainsAny(s, chars string) bool
字符包含判断
strings.Index(s, substr) int
定位(Rabin-Karp 算法)
strings.Count(s, substr) int
字符计算(Rabin-Karp 算法)
注意:任何字符串包含 n + 1 个空字符串
strings.HasPrefix(s, substr) bool
startswith
strings.HasSuffix(s, substr) bool
endswith
strings.Compare(s1, s2)
大于 1 / 小于 -1 / 等于 0
strings.Repeat(s, num) string
替换子串
strings.Replace(s, substr, replacement, num) string
strings.EqualFold(s1, s2) bool
忽略大小写等于判断
strings.Fields(s)
用空白字符(空格、换行、tab)将字符串切割成字串
strings.Split(s, sep string) []string
切割字符串
strings.SplitAfter(s, sep string) []string
切割字符串(包含分隔符)
strings.SplitAfterN(s, sep string, n int) []string
strings.SplitN(s, sep string, n int) []string
参考 Golang strings
包。
字符串连接:
+
, +=
fmt.Sprintf
strings.Join
bytes.Buffer
var b bytes.Buffer
b.WriteString("hello")
b.WriteString(" world")
fmt.Println(b.String())
var sb strings.Builder
sb.WriteString("hello")
sb.WriteString(" world")
fmt.Println(sb.String())
Golang 正则表达式
2020-12-06
Compile 系列
func Compile(expr string) (*Regexp, error)
func CompilePOSIX(expr string) (*Regexp, error)
func MustCompile(str string) *Regexp
func MustCompilePOSIX(str string) *Regexp
函数名称中的 Must 表示:如果正则错误,直接 panic
Match 系列
func (re *Regexp) Match(b []byte) bool
func (re *Regexp) MatchReader(r io.RuneReader) bool
func (re *Regexp) MatchString(s string) bool
Find 系列
func (re *Regexp) Find(b []byte) []byte
func (re *Regexp) FindAll(b []byte, n int) [][]byte
func (re *Regexp) FindAllIndex(b []byte, n int) [][]int
func (re *Regexp) FindAllString(s string, n int) []string
func (re *Regexp) FindAllStringIndex(s string, n int) [][]int
func (re *Regexp) FindAllStringSubmatch(s string, n int) [][]string
func (re *Regexp) FindAllStringSubmatchIndex(s string, n int) [][]int
func (re *Regexp) FindAllSubmatch(b []byte, n int) [][][]byte
func (re *Regexp) FindAllSubmatchIndex(b []byte, n int) [][]int
func (re *Regexp) FindIndex(b []byte) (loc []int)
func (re *Regexp) FindReaderIndex(r io.RuneReader) (loc []int)
func (re *Regexp) FindReaderSubmatchIndex(r io.RuneReader) []int
func (re *Regexp) FindString(s string) string
func (re *Regexp) FindStringIndex(s string) (loc []int)
func (re *Regexp) FindStringSubmatch(s string) []string
func (re *Regexp) FindStringSubmatchIndex(s string) []int
func (re *Regexp) FindSubmatch(b []byte) [][]byte
func (re *Regexp) FindSubmatchIndex(b []byte) []int
其实好记,Find(All)?(String)?(Submatch)?(Index)?
一组合就有 16 种了,再加上两个 FindReader
方法。
Replace 系列
func (re *Regexp) ReplaceAll(src, repl []byte) []byte
func (re *Regexp) ReplaceAllFunc(src []byte, repl func([]byte) []byte) []byte
func (re *Regexp) ReplaceAllLiteral(src, repl []byte) []byte
func (re *Regexp) ReplaceAllLiteralString(src, repl string) string
func (re *Regexp) ReplaceAllString(src, repl string) string
func (re *Regexp) ReplaceAllStringFunc(src string, repl func(string) string) string
其他
func (re *Regexp) Copy() *Regexp // DEPRECATED
func (re *Regexp) Expand(dst []byte, template []byte, src []byte, match []int) []byte
func (re *Regexp) ExpandString(dst []byte, template string, src string, match []int) []byte
func (re *Regexp) LiteralPrefix() (prefix string, complete bool)
func (re *Regexp) Longest()
func (re *Regexp) NumSubexp() int
func (re *Regexp) Split(s string, n int) []string
func (re *Regexp) String() string
func (re *Regexp) SubexpIndex(name string) int
func (re *Regexp) SubexpNames() []string
四个封装方法
func Match(pattern string, b []byte) (matched bool, err error)
func MatchReader(pattern string, r io.RuneReader) (matched bool, err error)
func MatchString(pattern string, s string) (matched bool, err error)
func QuoteMeta(s string) string
示例
func main() {
text := "Hello, 2021! The year 2020 was great, but 2021 will be even better."
pattern := `\b\d{4}\b` // 匹配四个数字的单词
regex, err := regexp.Compile(pattern)
if err != nil {
fmt.Println("Error compiling regex:", err)
return
}
matches := regex.FindAllString(text, -1)
for _, match := range matches {
fmt.Println(match)
}
}
Output:
2021
2020
2021