✨ init
This commit is contained in:
commit
e6ee860fd9
29
.gitignore
vendored
Normal file
29
.gitignore
vendored
Normal file
|
@ -0,0 +1,29 @@
|
|||
### Go template
|
||||
# If you prefer the allow list template instead of the deny list, see community template:
|
||||
# https://github.com/github/gitignore/blob/main/community/Golang/Go.AllowList.gitignore
|
||||
#
|
||||
# Binaries for programs and plugins
|
||||
*.exe
|
||||
*.exe~
|
||||
*.dll
|
||||
*.so
|
||||
*.dylib
|
||||
|
||||
# Test binary, built with `go test -c`
|
||||
*.test
|
||||
|
||||
# Output of the go coverage tool, specifically when used with LiteIDE
|
||||
*.out
|
||||
|
||||
# Dependency directories (remove the comment below to include it)
|
||||
# vendor/
|
||||
|
||||
# Go workspace file
|
||||
go.work
|
||||
|
||||
.idea
|
||||
# .vscode
|
||||
app.env
|
||||
|
||||
.DS_Store
|
||||
*/.DS_Store
|
7
.vscode/settings.json
vendored
Normal file
7
.vscode/settings.json
vendored
Normal file
|
@ -0,0 +1,7 @@
|
|||
{
|
||||
"go.autocompleteUnimportedPackages": true,
|
||||
"go.testFlags": [
|
||||
"-v",
|
||||
"-cover"
|
||||
]
|
||||
}
|
73
README.MD
Normal file
73
README.MD
Normal file
|
@ -0,0 +1,73 @@
|
|||
# Go学习
|
||||
|
||||
### 编写hello world程序
|
||||
- package 必须是 main
|
||||
- 方法名必须是 main()
|
||||
- 文件名不一定是 main.go
|
||||
|
||||
### 和其他语言差异
|
||||
- Go中 main 函数不支持任何返回值
|
||||
- 通过os.Exit来返回状态
|
||||
- main 函数不支持传入参数
|
||||
- 通过 os.Args 获取命令行参数
|
||||
|
||||
### 编写测试程序
|
||||
1. 源码文件以 `_test` 结尾: xxx_test.go
|
||||
2. 测试方法名以 Test 开头: func TestXXX(t *testing.T) {...}
|
||||
|
||||
|
||||
### 变量赋值
|
||||
- 赋值可以自动进行类型推断
|
||||
- 在一个赋值语句中可以对多个变量进行同时赋值
|
||||
```go
|
||||
// 单独赋值
|
||||
var a int = 1
|
||||
var b int = 1
|
||||
|
||||
// 同时赋值
|
||||
var (
|
||||
a int = 1
|
||||
b int = 1
|
||||
)
|
||||
|
||||
// 自动推断
|
||||
a := 1
|
||||
b := 1
|
||||
```
|
||||
|
||||
### 基本数据类型
|
||||
|
||||
```go
|
||||
bool
|
||||
string
|
||||
int int8 int16 int32 int64
|
||||
uint uint8 uint16 uint32 uint64 uintptr
|
||||
byte // alias for uint8
|
||||
rune // alias for int32, represents a Unicode code point
|
||||
float32 float64
|
||||
complex64 complex128
|
||||
```
|
||||
|
||||
### 类型转化
|
||||
- 与其他编程语言的差异
|
||||
1. Go不允许隐式类型转换
|
||||
2. 别名和原有类型也不能进行隐式类型转换
|
||||
|
||||
- 类型的预定义值
|
||||
1. math.MaxInt64
|
||||
2. math.MaxFloat64
|
||||
3. math.MaxUint32
|
||||
|
||||
|
||||
### 算术运算符
|
||||
- Go语言没有前置的 ++, --,
|
||||
|
||||
|
||||
### 线程和协程 Thread vs. Groutine
|
||||
|
||||
1. 创建时默认的 stack (栈) 的大小
|
||||
- JDK5 以后 Java Thread stack 默认为 1M
|
||||
- Groutine 的 stack 初始化大小为 2k
|
||||
2. 和 KSE (Kernel Speace Entity) 的对应关系
|
||||
- Java Thread 是 1:1
|
||||
- Groutine 是 M:N
|
5
go.mod
Normal file
5
go.mod
Normal file
|
@ -0,0 +1,5 @@
|
|||
module go_study
|
||||
|
||||
go 1.20
|
||||
|
||||
require github.com/go-playground/assert/v2 v2.2.0
|
2
go.sum
Normal file
2
go.sum
Normal file
|
@ -0,0 +1,2 @@
|
|||
github.com/go-playground/assert/v2 v2.2.0 h1:JvknZsQTYeFEAhQwI4qEt9cyV5ONwRHC+lYKSsYSR8s=
|
||||
github.com/go-playground/assert/v2 v2.2.0/go.mod h1:VDjEfimB/XKnb+ZQfWdccd7VUvScMdVu0Titje2rxJ4=
|
60
src/c10_func/func_test.go
Normal file
60
src/c10_func/func_test.go
Normal file
|
@ -0,0 +1,60 @@
|
|||
package func_test
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"math/rand"
|
||||
"testing"
|
||||
"time"
|
||||
)
|
||||
|
||||
// 多返回值函数
|
||||
func returnMultiValues() (int, int) {
|
||||
return rand.Intn(10), rand.Intn(20)
|
||||
}
|
||||
|
||||
// 函数用法之一: 统计执行时间
|
||||
func timeSpent(inner func(op int) int) func(op int) int {
|
||||
return func(n int) int {
|
||||
start := time.Now()
|
||||
ret := inner(n)
|
||||
fmt.Println("time spent: ", time.Since(start).Seconds())
|
||||
return ret
|
||||
}
|
||||
}
|
||||
|
||||
func slowFun(op int) int {
|
||||
time.Sleep(time.Second * 1)
|
||||
return op
|
||||
}
|
||||
|
||||
func TestFn(t *testing.T) {
|
||||
a, b := returnMultiValues()
|
||||
t.Log(a, b)
|
||||
|
||||
tsSF := timeSpent(slowFun)
|
||||
t.Log(tsSF(10))
|
||||
}
|
||||
|
||||
// 求和
|
||||
func Sum(ops ...int) int {
|
||||
ret := 0
|
||||
for _, op := range ops {
|
||||
ret += op
|
||||
}
|
||||
return ret
|
||||
}
|
||||
|
||||
func TestVarParam(t *testing.T) {
|
||||
t.Log(Sum(1, 3, 5, 7, 9, 2, 6))
|
||||
}
|
||||
|
||||
func Clear() {
|
||||
fmt.Println("Clear resources")
|
||||
}
|
||||
|
||||
// defer 延迟执行 一般用于资源的释放和异常的捕捉
|
||||
func TestDefer(t *testing.T) {
|
||||
defer Clear()
|
||||
fmt.Println("Start")
|
||||
panic("program error") //抛出异常
|
||||
}
|
29
src/c11_customer_type/customer_type_test.go
Normal file
29
src/c11_customer_type/customer_type_test.go
Normal file
|
@ -0,0 +1,29 @@
|
|||
package customer_tpye_test
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"testing"
|
||||
"time"
|
||||
)
|
||||
|
||||
// 自定义类型
|
||||
type IntConv func(op int) int
|
||||
|
||||
func timeSpent(inner IntConv) IntConv {
|
||||
return func(n int) int {
|
||||
start := time.Now()
|
||||
ret := inner(n)
|
||||
fmt.Println("time spent: ", time.Since(start).Seconds())
|
||||
return ret
|
||||
}
|
||||
}
|
||||
|
||||
func slowFun(op int) int {
|
||||
time.Sleep(time.Second * 1)
|
||||
return op
|
||||
}
|
||||
|
||||
func TestFn(t *testing.T) {
|
||||
tsSF := timeSpent(slowFun)
|
||||
t.Log(tsSF(10))
|
||||
}
|
48
src/c11_encapsulate/encap_test.go
Normal file
48
src/c11_encapsulate/encap_test.go
Normal file
|
@ -0,0 +1,48 @@
|
|||
package encap_test
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"testing"
|
||||
"unsafe"
|
||||
)
|
||||
|
||||
type Employee struct {
|
||||
Id string
|
||||
Name string
|
||||
Age int
|
||||
}
|
||||
|
||||
// 指针形式 复用 推荐使用
|
||||
func (e *Employee) String() string {
|
||||
fmt.Printf("Address is %x \n", unsafe.Pointer(&e.Name))
|
||||
return fmt.Sprintf("Id: %s, Name: %s, Age: %d", e.Id, e.Name, e.Age)
|
||||
}
|
||||
|
||||
// 数据复制, 地址变了
|
||||
// func (e Employee) String() string {
|
||||
// fmt.Printf("Address is %x \n", unsafe.Pointer(&e.Name))
|
||||
// return fmt.Sprintf("Id: %s, Name: %s, Age: %d", e.Id, e.Name, e.Age)
|
||||
// }
|
||||
|
||||
func TestCreateEmployeeObj(t *testing.T) {
|
||||
e := Employee{"1", "Frank", 20}
|
||||
e1 := Employee{Name: "Mike", Age: 28}
|
||||
e2 := new(Employee) //返回指针
|
||||
e2.Id = "3"
|
||||
e2.Name = "Jack"
|
||||
e2.Age = 32
|
||||
|
||||
t.Log(e)
|
||||
t.Log(e1)
|
||||
t.Log(e1.Id) //空字符串
|
||||
t.Log(e2)
|
||||
|
||||
t.Logf("e is %T", e)
|
||||
t.Logf("e2 is %T", e2)
|
||||
}
|
||||
|
||||
func TestStructOperations(t *testing.T) {
|
||||
e := Employee{"1", "Frank", 20}
|
||||
fmt.Printf("Address is %x \n", unsafe.Pointer(&e.Name))
|
||||
t.Log(e.String())
|
||||
}
|
20
src/c11_interface/interface_test.go
Normal file
20
src/c11_interface/interface_test.go
Normal file
|
@ -0,0 +1,20 @@
|
|||
package interface_test
|
||||
|
||||
import "testing"
|
||||
|
||||
type Programmer interface {
|
||||
WriteWord() string
|
||||
}
|
||||
|
||||
type GoProgrammer struct {
|
||||
}
|
||||
|
||||
func (p *GoProgrammer) WriteWord() string {
|
||||
return "hello world"
|
||||
}
|
||||
|
||||
func TestClient(t *testing.T) {
|
||||
var p Programmer
|
||||
p = new(GoProgrammer)
|
||||
t.Log(p.WriteWord())
|
||||
}
|
68
src/c12_extend/extension_test.go
Normal file
68
src/c12_extend/extension_test.go
Normal file
|
@ -0,0 +1,68 @@
|
|||
package extension_test
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"testing"
|
||||
)
|
||||
|
||||
// golang是可以实现继承的,但是这种继承并不是严格意义上的继承,
|
||||
// golang并不支持继承特性,因而也没有单继承,多继承,重写方法等复杂概念。
|
||||
|
||||
type Pet struct {
|
||||
}
|
||||
|
||||
func (p *Pet) Speak() {
|
||||
fmt.Println("...")
|
||||
}
|
||||
|
||||
func (p *Pet) SpeakTo(host string) {
|
||||
p.Speak()
|
||||
fmt.Println(host)
|
||||
}
|
||||
|
||||
// 有名继承
|
||||
|
||||
type Dog struct {
|
||||
p *Pet
|
||||
}
|
||||
|
||||
func (d *Dog) Speak() {
|
||||
fmt.Println("汪汪汪!")
|
||||
}
|
||||
|
||||
func TestDog(t *testing.T) {
|
||||
dog := new(Dog)
|
||||
dog.Speak()
|
||||
// dog.SpeakTo("Zhang") Dog没有这个方法, 虽然Pet有,但是此时Dog不是匿名继承 ,如果要要调用需要指定继承事指定的名称。
|
||||
dog.p.Speak()
|
||||
dog.p.SpeakTo("Li")
|
||||
}
|
||||
|
||||
// 匿名继承
|
||||
|
||||
type People struct {
|
||||
}
|
||||
|
||||
func (p *People) ShowA() {
|
||||
fmt.Println("AAA")
|
||||
}
|
||||
|
||||
func (p *People) ShowB() {
|
||||
fmt.Println("BBB")
|
||||
}
|
||||
|
||||
type Doctor struct {
|
||||
People
|
||||
}
|
||||
|
||||
func (p *Doctor) ShowA() {
|
||||
fmt.Println("Doctor AAA")
|
||||
}
|
||||
|
||||
func TestDoctor(t *testing.T) {
|
||||
d := new(Doctor)
|
||||
d.ShowA()
|
||||
d.ShowB() // 因为Teacher没有ShowB()的方法,此时又匿名继承了People,所以会调到People实现的ShowB方法
|
||||
d.People.ShowA()
|
||||
d.People.ShowB()
|
||||
}
|
41
src/c12_polymorphism/polymorphism_test.go
Normal file
41
src/c12_polymorphism/polymorphism_test.go
Normal file
|
@ -0,0 +1,41 @@
|
|||
package polymorphism
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"testing"
|
||||
)
|
||||
|
||||
// 多态
|
||||
|
||||
type Code string
|
||||
|
||||
type Programmer interface {
|
||||
WriteHelloWorld() Code
|
||||
}
|
||||
|
||||
type GoProgrammer struct {
|
||||
}
|
||||
|
||||
func (gp *GoProgrammer) WriteHelloWorld() Code {
|
||||
return "fmt.Println(\"hello world\")"
|
||||
}
|
||||
|
||||
type JavaProgrammer struct {
|
||||
}
|
||||
|
||||
func (jp *JavaProgrammer) WriteHelloWorld() Code {
|
||||
return "System.out.Println(\"hello world\")"
|
||||
}
|
||||
|
||||
func writeFirstProgram(p Programmer) {
|
||||
// %T 输出类型
|
||||
fmt.Printf("%T %v\n", p, p.WriteHelloWorld())
|
||||
}
|
||||
|
||||
func TestPolymorphism(t *testing.T) {
|
||||
gp := new(GoProgrammer)
|
||||
// gp := &GoProgrammer{}
|
||||
jp := new(JavaProgrammer)
|
||||
writeFirstProgram(gp)
|
||||
writeFirstProgram(jp)
|
||||
}
|
40
src/c13_empty_interface/empty_interface_test.go
Normal file
40
src/c13_empty_interface/empty_interface_test.go
Normal file
|
@ -0,0 +1,40 @@
|
|||
package empty_interface
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"testing"
|
||||
)
|
||||
|
||||
// 空接口与断言
|
||||
// 1.空接口可以表示任何类型
|
||||
// 2.通过断言来将空接口转换为制定类型
|
||||
|
||||
// 空接口入参
|
||||
func DoSomething(p interface{}) {
|
||||
// if i, ok := p.(int); ok {
|
||||
// fmt.Println("Integer", i)
|
||||
// return
|
||||
// }
|
||||
|
||||
// if s, ok := p.(string); ok {
|
||||
// fmt.Println("String", s)
|
||||
// return
|
||||
// }
|
||||
|
||||
// fmt.Println("Unknown Type")
|
||||
switch v := p.(type) {
|
||||
case int:
|
||||
fmt.Println("Integer", v)
|
||||
case string:
|
||||
fmt.Println("String", v)
|
||||
default:
|
||||
fmt.Println("Unknown Type")
|
||||
}
|
||||
}
|
||||
|
||||
// 测试空接口入参断言
|
||||
func TestEmptyInterfaceAssertion(t *testing.T) {
|
||||
DoSomething(10)
|
||||
DoSomething("1231")
|
||||
DoSomething(8.88)
|
||||
}
|
45
src/c14_error_test/error_test.go
Normal file
45
src/c14_error_test/error_test.go
Normal file
|
@ -0,0 +1,45 @@
|
|||
package error_test
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"testing"
|
||||
)
|
||||
|
||||
/*
|
||||
|
||||
Go的错误机制
|
||||
1.没有异常机制
|
||||
2.error类型实现了error接口
|
||||
3.可以通过 errors.New 来快速创建错误实例
|
||||
|
||||
*/
|
||||
|
||||
var ErrorLessThanTwo = errors.New("n should be not less than 2")
|
||||
var ErrorLargerThenHundred = errors.New("n should be not larger than 100")
|
||||
|
||||
func GetFibonacci(n int) ([]int, error) {
|
||||
if n < 2 {
|
||||
return nil, ErrorLessThanTwo
|
||||
}
|
||||
if n > 100 {
|
||||
return nil, ErrorLargerThenHundred
|
||||
}
|
||||
fibList := []int{1, 1}
|
||||
for i := 2; i < n; i++ {
|
||||
fibList = append(fibList, fibList[i-2]+fibList[i-1])
|
||||
}
|
||||
return fibList, nil
|
||||
}
|
||||
|
||||
func TestGetFibonacci(t *testing.T) {
|
||||
if ret, err := GetFibonacci(-10); err != nil {
|
||||
if err == ErrorLessThanTwo {
|
||||
fmt.Println("It is less.")
|
||||
}
|
||||
t.Error(err)
|
||||
} else {
|
||||
t.Log(ret)
|
||||
}
|
||||
|
||||
}
|
34
src/c14_panic_recover/panic_recover_test.go
Normal file
34
src/c14_panic_recover/panic_recover_test.go
Normal file
|
@ -0,0 +1,34 @@
|
|||
package panic_recover
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"testing"
|
||||
)
|
||||
|
||||
// Let it Crash 往往是恢复不确定性错误的最好方法
|
||||
// panic 用于不可以恢复的错误
|
||||
// panic 退出前会执行 defer 指定的内容
|
||||
|
||||
// os.Exit 退出时不会调用 defer 指定的函数
|
||||
// os.Exit 退出时不输出当前调用栈信息
|
||||
|
||||
// 常见的错误恢复 recover()
|
||||
// 当心 recover 成为"恶魔" 形成僵尸服务进程 导致health check失效
|
||||
|
||||
func TestPanicVxExit(t *testing.T) {
|
||||
// defer func () {
|
||||
// fmt.Println("Finally")
|
||||
// }()
|
||||
|
||||
defer func() {
|
||||
// recover() 错误恢复 小心使用
|
||||
if err := recover(); err != nil {
|
||||
fmt.Println("recovered from ", err)
|
||||
}
|
||||
}()
|
||||
fmt.Println("Start")
|
||||
panic(errors.New("Something wrong!"))
|
||||
// os.Exit(-1)
|
||||
// fmt.Println("end")
|
||||
}
|
18
src/c15_package_test/package_test.go
Normal file
18
src/c15_package_test/package_test.go
Normal file
|
@ -0,0 +1,18 @@
|
|||
package client
|
||||
|
||||
import (
|
||||
"go_study/src/c15_package_test/series"
|
||||
"testing"
|
||||
)
|
||||
|
||||
// 可复用模块 包
|
||||
// 基本复用单元 以首字母大写来表明可被包外代码访问
|
||||
// 代码的 package 可以和所在的目录不一致
|
||||
// 同一目录里的 Go 代码的 package 要保持一致
|
||||
|
||||
// 测试复用方法
|
||||
func TestPackage(t *testing.T) {
|
||||
t.Log(series.GetFibonacciSeries(5))
|
||||
|
||||
// t.Log(series.getSlice()) // 报错 无法访问
|
||||
}
|
14
src/c15_package_test/series/my_series.go
Normal file
14
src/c15_package_test/series/my_series.go
Normal file
|
@ -0,0 +1,14 @@
|
|||
package series
|
||||
|
||||
// GetFibonacciSeries 实现 斐波那契数列
|
||||
func GetFibonacciSeries(n int) []int {
|
||||
fibList := []int{1, 1}
|
||||
for i := 2; i < n; i++ {
|
||||
fibList = append(fibList, fibList[i-2]+fibList[i-1])
|
||||
}
|
||||
return fibList
|
||||
}
|
||||
|
||||
func getSlice() []int {
|
||||
return []int{1, 2, 3, 4, 5}
|
||||
}
|
18
src/c16_groutine/groutine_test.go
Normal file
18
src/c16_groutine/groutine_test.go
Normal file
|
@ -0,0 +1,18 @@
|
|||
package groutine_test
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"testing"
|
||||
"time"
|
||||
)
|
||||
|
||||
// 测试协程机制
|
||||
func TestGroutine(t *testing.T) {
|
||||
for i := 0; i < 10; i++ {
|
||||
// 协程
|
||||
go func(i int) {
|
||||
fmt.Println(i)
|
||||
}(i)
|
||||
}
|
||||
time.Sleep(time.Millisecond * 50)
|
||||
}
|
89
src/c17_share_memory/share_mem_test.go
Normal file
89
src/c17_share_memory/share_mem_test.go
Normal file
|
@ -0,0 +1,89 @@
|
|||
package share_mem
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"sync"
|
||||
"testing"
|
||||
"time"
|
||||
)
|
||||
|
||||
// 共享内存并发机制
|
||||
|
||||
func TestCounter(t *testing.T) {
|
||||
counter := 0
|
||||
for i := 0; i < 5000; i++ {
|
||||
go func() {
|
||||
// 不安全的写法
|
||||
counter++
|
||||
}()
|
||||
}
|
||||
time.Sleep(time.Second * 1)
|
||||
t.Logf("counter= %d", counter) // 得到的结果会小于 5000
|
||||
}
|
||||
|
||||
// Mutex的使用
|
||||
func TestCounterThread(t *testing.T) {
|
||||
var mut sync.Mutex
|
||||
counter := 0
|
||||
for i := 0; i < 5000; i++ {
|
||||
go func() {
|
||||
defer func() {
|
||||
mut.Unlock()
|
||||
}()
|
||||
mut.Lock()
|
||||
counter++
|
||||
}()
|
||||
}
|
||||
time.Sleep(time.Second * 1) //去掉 time.Sleep(), counter的结果不符合预期, 小于 5000
|
||||
t.Logf("counter= %d", counter)
|
||||
}
|
||||
|
||||
// 利用WaitGroup来确定所有任务是否结束
|
||||
func TestCounterWaitGroup(t *testing.T) {
|
||||
var mut sync.Mutex
|
||||
var wg sync.WaitGroup
|
||||
counter := 0
|
||||
for i := 0; i < 5000; i++ {
|
||||
wg.Add(1)
|
||||
go func() {
|
||||
defer func() {
|
||||
mut.Unlock()
|
||||
}()
|
||||
mut.Lock()
|
||||
counter++
|
||||
wg.Done()
|
||||
}()
|
||||
}
|
||||
wg.Wait() //挂起 等待完成
|
||||
t.Logf("counter= %d", counter)
|
||||
}
|
||||
|
||||
var rwMutex *sync.RWMutex
|
||||
var wg *sync.WaitGroup
|
||||
|
||||
// 读写锁
|
||||
func TestRWMutex(t *testing.T) {
|
||||
rwMutex = new(sync.RWMutex)
|
||||
wg = new(sync.WaitGroup)
|
||||
wg.Add(2)
|
||||
go readData(1)
|
||||
go readData(2)
|
||||
|
||||
wg.Wait()
|
||||
fmt.Println("func finish")
|
||||
}
|
||||
|
||||
func readData(i int) {
|
||||
defer wg.Done()
|
||||
fmt.Println(i, "start locking!")
|
||||
// 给读操作 上锁
|
||||
rwMutex.RLock()
|
||||
// 读数据
|
||||
fmt.Println(i, "Reading data")
|
||||
// 休眠1s
|
||||
time.Sleep(1 * time.Second)
|
||||
// 读解锁
|
||||
rwMutex.RUnlock()
|
||||
// 打印提示信息
|
||||
fmt.Println(i, "Read over")
|
||||
}
|
41
src/c18_csp/async_service_test.go
Normal file
41
src/c18_csp/async_service_test.go
Normal file
|
@ -0,0 +1,41 @@
|
|||
package csp_test
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"testing"
|
||||
"time"
|
||||
)
|
||||
|
||||
func service() string {
|
||||
time.Sleep(time.Millisecond * 50)
|
||||
return "Done"
|
||||
}
|
||||
|
||||
func otherTask() {
|
||||
fmt.Println("执行一些其他的任务")
|
||||
time.Sleep(time.Millisecond * 100)
|
||||
fmt.Println("任务完成")
|
||||
}
|
||||
|
||||
func TestService(t *testing.T) {
|
||||
fmt.Println(service())
|
||||
otherTask()
|
||||
}
|
||||
|
||||
func AsyncService() chan string {
|
||||
retChan := make(chan string, 1) // buffered channel (非阻塞、异步模式) 不会阻塞service
|
||||
// retChan := make(chan string) // unbuffered channel (阻塞、同步模式) 会阻塞service
|
||||
go func() {
|
||||
ret := service()
|
||||
fmt.Println("返回service结果")
|
||||
retChan <- ret
|
||||
fmt.Println("service已退出")
|
||||
}()
|
||||
return retChan
|
||||
}
|
||||
|
||||
func TestAsyncService(t *testing.T) {
|
||||
retCh := AsyncService()
|
||||
otherTask()
|
||||
fmt.Println(<-retCh)
|
||||
}
|
34
src/c19_select/select_test.go
Normal file
34
src/c19_select/select_test.go
Normal file
|
@ -0,0 +1,34 @@
|
|||
package select_test
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"testing"
|
||||
"time"
|
||||
)
|
||||
|
||||
func service() string {
|
||||
time.Sleep(time.Millisecond * 100)
|
||||
return "Done"
|
||||
}
|
||||
|
||||
func AsyncService() chan string {
|
||||
retChan := make(chan string, 1) // buffered channel (非阻塞、异步模式) 不会阻塞service
|
||||
// retChan := make(chan string) // unbuffered channel (阻塞、同步模式) 会阻塞service
|
||||
go func() {
|
||||
ret := service()
|
||||
fmt.Println("返回service结果")
|
||||
retChan <- ret
|
||||
fmt.Println("service已退出")
|
||||
}()
|
||||
return retChan
|
||||
}
|
||||
|
||||
// 多路选择 select 实现超时机制
|
||||
func TestSelect(t *testing.T) {
|
||||
select {
|
||||
case ret := <-AsyncService():
|
||||
t.Log(ret)
|
||||
case <-time.After(time.Millisecond * 100):
|
||||
t.Error("超时")
|
||||
}
|
||||
}
|
19
src/c1_hello_world/hello_world.go
Normal file
19
src/c1_hello_world/hello_world.go
Normal file
|
@ -0,0 +1,19 @@
|
|||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"os"
|
||||
)
|
||||
|
||||
// Go中 main 函数不支持任何返回值
|
||||
// main 函数不支持传入参数
|
||||
func main() {
|
||||
// 通过 os.Args 获取命令行参数
|
||||
fmt.Println(os.Args)
|
||||
fmt.Println("Hello Golang!")
|
||||
os.Exit(0) // 通过os.Exit来返回状态
|
||||
}
|
||||
|
||||
// package 必须是 main
|
||||
// 方法名必须是 main()
|
||||
// 文件名不一定是 main.go
|
43
src/c20_cancel_by_close/cancel_test.go
Normal file
43
src/c20_cancel_by_close/cancel_test.go
Normal file
|
@ -0,0 +1,43 @@
|
|||
package cancel_test
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"testing"
|
||||
"time"
|
||||
)
|
||||
|
||||
func isCancelled(cancelChan chan struct{}) bool {
|
||||
select {
|
||||
case <-cancelChan:
|
||||
return true
|
||||
default:
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
||||
func cancel1(cancelChan chan struct{}) {
|
||||
cancelChan <- struct{}{}
|
||||
}
|
||||
|
||||
func cancel2(cancelChan chan struct{}) {
|
||||
close(cancelChan)
|
||||
}
|
||||
|
||||
// 使用close来取消任务
|
||||
func TestCancel(t *testing.T) {
|
||||
cancelChan := make(chan struct{}, 0)
|
||||
for i := 0; i < 5; i++ {
|
||||
go func(i int, cancelChan chan struct{}) {
|
||||
for {
|
||||
if isCancelled(cancelChan) {
|
||||
break
|
||||
}
|
||||
time.Sleep(time.Millisecond * 5)
|
||||
}
|
||||
fmt.Println(i, "Done")
|
||||
}(i, cancelChan)
|
||||
}
|
||||
// cancel1(cancelChan)
|
||||
cancel2(cancelChan)
|
||||
time.Sleep(time.Second * 1)
|
||||
}
|
35
src/c20_cancel_by_context/cancel_by_context_test.go
Normal file
35
src/c20_cancel_by_context/cancel_by_context_test.go
Normal file
|
@ -0,0 +1,35 @@
|
|||
package cancel_by_context_test
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"testing"
|
||||
"time"
|
||||
)
|
||||
|
||||
func isCancelled(ctx context.Context) bool {
|
||||
select {
|
||||
case <-ctx.Done():
|
||||
return true
|
||||
default:
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
||||
// 使用context来取消任务
|
||||
func TestCancel(t *testing.T) {
|
||||
ctx, cancel := context.WithCancel(context.Background())
|
||||
for i := 0; i < 5; i++ {
|
||||
go func(i int, ctx context.Context) {
|
||||
for {
|
||||
if isCancelled(ctx) {
|
||||
break
|
||||
}
|
||||
time.Sleep(time.Millisecond * 5)
|
||||
}
|
||||
fmt.Println(i, "Done")
|
||||
}(i, ctx)
|
||||
}
|
||||
cancel()
|
||||
time.Sleep(time.Second * 1)
|
||||
}
|
56
src/c20_channel_close/channel_close_test.go
Normal file
56
src/c20_channel_close/channel_close_test.go
Normal file
|
@ -0,0 +1,56 @@
|
|||
package channel_close_test
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"sync"
|
||||
"testing"
|
||||
)
|
||||
|
||||
// 生产者
|
||||
func dataProducer(ch chan int, wg *sync.WaitGroup) {
|
||||
go func() {
|
||||
for i := 0; i < 10; i++ {
|
||||
ch <- i
|
||||
}
|
||||
close(ch) // 关闭channel
|
||||
wg.Done()
|
||||
}()
|
||||
}
|
||||
|
||||
// 消费者
|
||||
// func dataReceiver(ch chan int, wg *sync.WaitGroup) {
|
||||
// go func() {
|
||||
// for i := 0; i < 10; i++ {
|
||||
// data := <-ch
|
||||
// fmt.Println(data)
|
||||
// }
|
||||
// wg.Done()
|
||||
// }()
|
||||
// }
|
||||
|
||||
func dataReceiver(ch chan int, wg *sync.WaitGroup) {
|
||||
go func() {
|
||||
for {
|
||||
if data, ok := <-ch; ok {
|
||||
fmt.Println(data)
|
||||
} else {
|
||||
// 通道关闭 去获取值会立即返回通道定义类型的默认值
|
||||
fmt.Println(data)
|
||||
break
|
||||
}
|
||||
}
|
||||
wg.Done()
|
||||
}()
|
||||
}
|
||||
|
||||
func TestCloseChannel(t *testing.T) {
|
||||
var wg sync.WaitGroup
|
||||
ch := make(chan int)
|
||||
wg.Add(1)
|
||||
dataProducer(ch, &wg)
|
||||
wg.Add(1)
|
||||
dataReceiver(ch, &wg)
|
||||
wg.Add(1)
|
||||
dataReceiver(ch, &wg)
|
||||
wg.Wait()
|
||||
}
|
37
src/c21_singleton/once_test.go
Normal file
37
src/c21_singleton/once_test.go
Normal file
|
@ -0,0 +1,37 @@
|
|||
package once_test
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"sync"
|
||||
"testing"
|
||||
"unsafe"
|
||||
)
|
||||
|
||||
// 利用sync.Once实现 单例模式
|
||||
|
||||
type Singleton struct {
|
||||
}
|
||||
|
||||
var singletonInstance *Singleton
|
||||
var once sync.Once
|
||||
|
||||
func GetSingletonObj() *Singleton {
|
||||
once.Do(func() {
|
||||
fmt.Println("创建对象")
|
||||
singletonInstance = new(Singleton)
|
||||
})
|
||||
return singletonInstance
|
||||
}
|
||||
|
||||
func TestGetSingletonObj(t *testing.T) {
|
||||
var wg sync.WaitGroup
|
||||
for i := 0; i < 10; i++ {
|
||||
wg.Add(1)
|
||||
go func() {
|
||||
obj := GetSingletonObj()
|
||||
t.Logf("%x", unsafe.Pointer(obj))
|
||||
wg.Done()
|
||||
}()
|
||||
}
|
||||
wg.Wait()
|
||||
}
|
33
src/c22_util_anyone_reply/first_response_test.go
Normal file
33
src/c22_util_anyone_reply/first_response_test.go
Normal file
|
@ -0,0 +1,33 @@
|
|||
package util_anyone_reply
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"runtime"
|
||||
"testing"
|
||||
"time"
|
||||
)
|
||||
|
||||
func runTask(id int) string {
|
||||
time.Sleep(time.Millisecond * 10)
|
||||
return fmt.Sprintf("结果来自: %d", id)
|
||||
}
|
||||
|
||||
func FirstResponse() string {
|
||||
numOfRunner := 10
|
||||
// 使用 buffered channel (非阻塞、异步模式) 来防止协程泄露
|
||||
ch := make(chan string, numOfRunner)
|
||||
for i := 0; i < numOfRunner; i++ {
|
||||
go func(i int) {
|
||||
ret := runTask(i)
|
||||
ch <- ret
|
||||
}(i)
|
||||
}
|
||||
return <-ch
|
||||
}
|
||||
|
||||
func TestFirstResponse(t *testing.T) {
|
||||
t.Log("Before 当前系统协程数: ", runtime.NumGoroutine())
|
||||
t.Log(FirstResponse())
|
||||
time.Sleep(time.Second * 1)
|
||||
t.Log("After 当前协程数: ", runtime.NumGoroutine())
|
||||
}
|
36
src/c23_util_all_done/all_done_test.go
Normal file
36
src/c23_util_all_done/all_done_test.go
Normal file
|
@ -0,0 +1,36 @@
|
|||
package util_all_done
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"runtime"
|
||||
"testing"
|
||||
"time"
|
||||
)
|
||||
|
||||
func runTask(id int) string {
|
||||
time.Sleep(time.Millisecond * 10)
|
||||
return fmt.Sprintf("结果来自: %d", id)
|
||||
}
|
||||
|
||||
func AllResponse() string {
|
||||
numOfRunner := 10
|
||||
ch := make(chan string, numOfRunner)
|
||||
for i := 0; i < numOfRunner; i++ {
|
||||
go func(i int) {
|
||||
ret := runTask(i)
|
||||
ch <- ret
|
||||
}(i)
|
||||
}
|
||||
finalRet := ""
|
||||
for j := 0; j < numOfRunner; j++ {
|
||||
finalRet += <-ch + "\n"
|
||||
}
|
||||
return finalRet
|
||||
}
|
||||
|
||||
func TestAllResponse(t *testing.T) {
|
||||
t.Log("Before 当前系统协程数: ", runtime.NumGoroutine())
|
||||
t.Log(AllResponse())
|
||||
time.Sleep(time.Second * 1)
|
||||
t.Log("After 当前协程数: ", runtime.NumGoroutine())
|
||||
}
|
42
src/c24_obj_pool/obj_pool.go
Normal file
42
src/c24_obj_pool/obj_pool.go
Normal file
|
@ -0,0 +1,42 @@
|
|||
package obj_pool
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"time"
|
||||
)
|
||||
|
||||
type MyObj struct {
|
||||
}
|
||||
|
||||
type ObjPool struct {
|
||||
buffChan chan *MyObj
|
||||
}
|
||||
|
||||
// 利用channel实现的对象池
|
||||
|
||||
func NewObjPool(num int) *ObjPool {
|
||||
objPool := ObjPool{}
|
||||
objPool.buffChan = make(chan *MyObj, num)
|
||||
for i := 0; i < num; i++ {
|
||||
objPool.buffChan <- &MyObj{}
|
||||
}
|
||||
return &objPool
|
||||
}
|
||||
|
||||
func (p *ObjPool) GetObj(timeout time.Duration) (*MyObj, error) {
|
||||
select {
|
||||
case ret := <-p.buffChan:
|
||||
return ret, nil
|
||||
case <-time.After(timeout): // 超时控制
|
||||
return nil, errors.New("超时")
|
||||
}
|
||||
}
|
||||
|
||||
func (p *ObjPool) PutObj(obj *MyObj) error {
|
||||
select {
|
||||
case p.buffChan <- obj:
|
||||
return nil
|
||||
default:
|
||||
return errors.New("超出对象池最大容量")
|
||||
}
|
||||
}
|
27
src/c24_obj_pool/obj_pool_test.go
Normal file
27
src/c24_obj_pool/obj_pool_test.go
Normal file
|
@ -0,0 +1,27 @@
|
|||
package obj_pool
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"testing"
|
||||
"time"
|
||||
)
|
||||
|
||||
func TestObjPool(t *testing.T) {
|
||||
num := 10
|
||||
pool := NewObjPool(num)
|
||||
//if err := pool.PutObj(&MyObj{}); err != nil { // 尝试防止超出池大小的对象
|
||||
// t.Error(err)
|
||||
//}
|
||||
for i := 0; i < num; i++ {
|
||||
if obj, err := pool.GetObj(time.Second * 1); err != nil {
|
||||
t.Error(err)
|
||||
} else {
|
||||
fmt.Printf("%T\n", obj)
|
||||
if err := pool.PutObj(obj); err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
t.Log("Done.")
|
||||
}
|
22
src/c25_obj_cache/README.MD
Normal file
22
src/c25_obj_cache/README.MD
Normal file
|
@ -0,0 +1,22 @@
|
|||
### sync.Pool 对象获取
|
||||
|
||||
- 尝试从私有对象获取
|
||||
- 私有对象不存在, 尝试从当前Processor的共享池获取
|
||||
- 如果当前Processor共享池也是空的,那么就尝试去其他Processor的共享池获取
|
||||
- 如果所有子池都是空的, 最后就用用户指定的New函数产生一个新的对象返回
|
||||
|
||||
### sync.Pool 对象的生命周期
|
||||
|
||||
- GC会清除sync.pool缓存的对象
|
||||
- 对象的缓存有效期为下一次GC之前
|
||||
|
||||
### sync.Pool对象的放回
|
||||
|
||||
- 如果私有对象不存在则保存为私有对象
|
||||
- 如果私有对象存在, 放入当前Processor子池的共享池中
|
||||
|
||||
### sync.Pool总结
|
||||
|
||||
- 适合于通过复用, 降低复杂对象的创建和GC代价
|
||||
- 协程安全, 会有锁的开销
|
||||
- 生命周期受GC影响, 不适合于做连接池等, 需自己管理生命周期的资源的池化
|
51
src/c25_obj_cache/sync_pool_test.go
Normal file
51
src/c25_obj_cache/sync_pool_test.go
Normal file
|
@ -0,0 +1,51 @@
|
|||
package obj_cache
|
||||
|
||||
import (
|
||||
"runtime"
|
||||
"sync"
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestSyncPool(t *testing.T) {
|
||||
pool := &sync.Pool{
|
||||
New: func() interface{} {
|
||||
t.Log("Create a new object.")
|
||||
return 100
|
||||
},
|
||||
}
|
||||
|
||||
v := pool.Get().(int)
|
||||
t.Log(v)
|
||||
pool.Put(3)
|
||||
|
||||
v1 := pool.Get().(int)
|
||||
t.Log("put操作后: ", v1)
|
||||
runtime.GC() // GC 会清除sync.pool中缓存的对象
|
||||
v2, _ := pool.Get().(int)
|
||||
t.Log("GC操作后: ", v2)
|
||||
|
||||
}
|
||||
|
||||
// 协程测试
|
||||
func TestSyncPoolInMultiGroutine(t *testing.T) {
|
||||
pool := &sync.Pool{
|
||||
New: func() interface{} {
|
||||
t.Log("create object")
|
||||
return 10
|
||||
},
|
||||
}
|
||||
|
||||
pool.Put(100)
|
||||
pool.Put(100)
|
||||
pool.Put(100)
|
||||
|
||||
var wg sync.WaitGroup
|
||||
for i := 0; i < 10; i++ {
|
||||
wg.Add(1)
|
||||
go func(id int) {
|
||||
t.Log("从pool获取对象: ", pool.Get())
|
||||
wg.Done()
|
||||
}(i)
|
||||
}
|
||||
wg.Wait()
|
||||
}
|
5
src/c26_unit_test/functions.go
Normal file
5
src/c26_unit_test/functions.go
Normal file
|
@ -0,0 +1,5 @@
|
|||
package unit_test
|
||||
|
||||
func Square(i int) int {
|
||||
return i * i
|
||||
}
|
46
src/c26_unit_test/functions_test.go
Normal file
46
src/c26_unit_test/functions_test.go
Normal file
|
@ -0,0 +1,46 @@
|
|||
package unit_test
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"testing"
|
||||
|
||||
"github.com/go-playground/assert/v2"
|
||||
)
|
||||
|
||||
// 表格测试法
|
||||
func TestSquare(t *testing.T) {
|
||||
// 输入值
|
||||
inputs := [...]int{1, 2, 3}
|
||||
// 期待值
|
||||
expected := [...]int{1, 4, 9}
|
||||
for i := 0; i < len(inputs); i++ {
|
||||
ret := Square(inputs[i])
|
||||
if ret != expected[i] {
|
||||
t.Errorf("input is %d, the expected is %d, the actual %d", inputs[i], expected[i], ret)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestErrorInCode(t *testing.T) {
|
||||
fmt.Println("Start")
|
||||
t.Error("Error") // 程序继续执行
|
||||
fmt.Println("End")
|
||||
}
|
||||
|
||||
func TestFatalInCode(t *testing.T) {
|
||||
fmt.Println("Start")
|
||||
t.Fatal("Error") // 程序会中断 不会输出End
|
||||
fmt.Println("End")
|
||||
}
|
||||
|
||||
// 使用断言Assert测试
|
||||
func TestSquareWithAssert(t *testing.T) {
|
||||
// 输入值
|
||||
inputs := [...]int{1, 2, 3}
|
||||
// 期待值
|
||||
expected := [...]int{1, 4, 9}
|
||||
for i := 0; i < len(inputs); i++ {
|
||||
ret := Square(inputs[i])
|
||||
assert.Equal(t, expected[i], ret)
|
||||
}
|
||||
}
|
36
src/c2_const_test/constant_test.go
Normal file
36
src/c2_const_test/constant_test.go
Normal file
|
@ -0,0 +1,36 @@
|
|||
package constant_test
|
||||
|
||||
import "testing"
|
||||
|
||||
// 声明常量
|
||||
const (
|
||||
// 连续常量写法 借助 iota
|
||||
Monday = iota + 1
|
||||
Tuesday
|
||||
Wednesday
|
||||
)
|
||||
|
||||
const (
|
||||
// 位运算
|
||||
Readable = 1 << iota
|
||||
Writeable
|
||||
Executable
|
||||
)
|
||||
|
||||
const (
|
||||
Cat = 1
|
||||
Dog = 2
|
||||
Pig = 3
|
||||
)
|
||||
|
||||
func TestConstant(t *testing.T) {
|
||||
t.Log(Monday, Tuesday)
|
||||
}
|
||||
|
||||
func TestConstant1(t *testing.T) {
|
||||
a := 1
|
||||
t.Log(a&Readable, a&Writeable, a&Executable)
|
||||
|
||||
t.Log(a&Readable == Readable, a&Writeable == Writeable, a&Executable == Executable)
|
||||
|
||||
}
|
47
src/c2_const_test/fib_test/fib_test.go
Normal file
47
src/c2_const_test/fib_test/fib_test.go
Normal file
|
@ -0,0 +1,47 @@
|
|||
package fib
|
||||
|
||||
import (
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestFibList(t *testing.T) {
|
||||
// var a int = 1
|
||||
// var b int = 1
|
||||
|
||||
// var (
|
||||
// a int = 1
|
||||
// b int = 1
|
||||
// )
|
||||
|
||||
a := 1
|
||||
b := 1
|
||||
t.Log(a)
|
||||
for i := 0; i < 5; i++ {
|
||||
t.Log(b)
|
||||
tmp := a
|
||||
a = b
|
||||
b = tmp + a
|
||||
}
|
||||
}
|
||||
|
||||
func TestExchange(t *testing.T) {
|
||||
// 其他编程语言常见写法 借助中间变量tmp
|
||||
a := 1
|
||||
b := 2
|
||||
tmp := a
|
||||
a = b
|
||||
b = tmp
|
||||
t.Log(a, b)
|
||||
|
||||
// go 值替换
|
||||
a, b = b, a
|
||||
t.Log(a, b)
|
||||
}
|
||||
|
||||
func TestDemo(t *testing.T) {
|
||||
a := "123"
|
||||
b := "321"
|
||||
t.Log(&a, &b)
|
||||
a, b = b, a
|
||||
t.Log(&a, &b, a, b)
|
||||
}
|
9
src/c2_const_test/first_test.go
Normal file
9
src/c2_const_test/first_test.go
Normal file
|
@ -0,0 +1,9 @@
|
|||
package constant_test
|
||||
|
||||
import (
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestFirst(t *testing.T) {
|
||||
t.Log("我的第一个go测试程序!")
|
||||
}
|
39
src/c3_type_test/type_test.go
Normal file
39
src/c3_type_test/type_test.go
Normal file
|
@ -0,0 +1,39 @@
|
|||
package tpye_test
|
||||
|
||||
import (
|
||||
"math"
|
||||
"testing"
|
||||
)
|
||||
|
||||
// 自定义类型
|
||||
type MyInt int64
|
||||
|
||||
// 类型转换
|
||||
func TestImplicit(t *testing.T) {
|
||||
var a int32 = 1
|
||||
// 显示类型转换
|
||||
var b = int64(a)
|
||||
var c = MyInt(b)
|
||||
t.Log(a, b, c)
|
||||
}
|
||||
|
||||
// 指针
|
||||
func TestPoint(t *testing.T) {
|
||||
a := 1
|
||||
aPtr := &a
|
||||
t.Log(a, aPtr)
|
||||
t.Logf("%T %T", a, aPtr)
|
||||
}
|
||||
|
||||
func TestString(t *testing.T) {
|
||||
// 不赋值默认空字符串
|
||||
var s string
|
||||
t.Log("*" + s + "*")
|
||||
t.Log(len(s))
|
||||
t.Log(s == "")
|
||||
}
|
||||
|
||||
func TestMax(t *testing.T) {
|
||||
t.Log(math.MaxFloat64)
|
||||
t.Log(math.MaxInt64)
|
||||
}
|
30
src/c4_operator_test/operator_test.go
Normal file
30
src/c4_operator_test/operator_test.go
Normal file
|
@ -0,0 +1,30 @@
|
|||
package operator_test
|
||||
|
||||
import "testing"
|
||||
|
||||
// 数组比较
|
||||
func TestCompareArray(t *testing.T) {
|
||||
a := [...]int{1, 2, 3, 4}
|
||||
b := [...]int{1, 2, 3, 5}
|
||||
d := [...]int{1, 2, 3, 4}
|
||||
t.Log(a == b)
|
||||
//c := [...]int{1, 2, 3, 4, 5}
|
||||
//t.Log(a == c) //报错 长度不同不能比较
|
||||
t.Log(a == d)
|
||||
|
||||
}
|
||||
|
||||
const (
|
||||
// 位运算
|
||||
Readable = 1 << iota
|
||||
Writeable
|
||||
Executable
|
||||
)
|
||||
|
||||
func TestBitClear(t *testing.T) {
|
||||
a := 7
|
||||
a = a &^ Readable
|
||||
a = a &^ Executable
|
||||
t.Log(a&Readable, a&Writeable, a&Executable)
|
||||
t.Log(a&Readable == Readable, a&Writeable == Writeable, a&Executable == Executable)
|
||||
}
|
40
src/c5_condition/condition_test.go
Normal file
40
src/c5_condition/condition_test.go
Normal file
|
@ -0,0 +1,40 @@
|
|||
package condition_test
|
||||
|
||||
import "testing"
|
||||
|
||||
// if
|
||||
func TestIfMultiSec(t *testing.T) {
|
||||
if a := 1 == 1.0; a {
|
||||
t.Log("1 == 1")
|
||||
} else {
|
||||
t.Log("!=")
|
||||
}
|
||||
}
|
||||
|
||||
// switch
|
||||
func TestSwitchMultiCase(t *testing.T) {
|
||||
for i := 0; i < 5; i++ {
|
||||
switch i {
|
||||
case 0, 2:
|
||||
t.Log("偶数Even")
|
||||
case 1, 3:
|
||||
t.Log("基数Odd")
|
||||
default:
|
||||
t.Log("it is not 0-3")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// switch2
|
||||
func TestSwitchCaseCondition(t *testing.T) {
|
||||
for i := 0; i < 5; i++ {
|
||||
switch {
|
||||
case i%2 == 0:
|
||||
t.Log("偶数Even")
|
||||
case i%2 == 1:
|
||||
t.Log("基数Odd")
|
||||
default:
|
||||
t.Log("it is default case")
|
||||
}
|
||||
}
|
||||
}
|
39
src/c6_array_test/array_test.go
Normal file
39
src/c6_array_test/array_test.go
Normal file
|
@ -0,0 +1,39 @@
|
|||
package array_test
|
||||
|
||||
import "testing"
|
||||
|
||||
// 数组声明
|
||||
func TestArrayInit(t *testing.T) {
|
||||
var arr [3]int
|
||||
arr1 := [4]int{1, 2, 3, 4}
|
||||
arr3 := [...]int{1, 3, 4, 5}
|
||||
arr1[1] = 5
|
||||
t.Log(arr[1], arr[2])
|
||||
t.Log(arr1, arr3)
|
||||
}
|
||||
|
||||
// 数组遍历
|
||||
func TestArrayTravel(t *testing.T) {
|
||||
arr3 := [...]int{1, 3, 4, 5}
|
||||
for i := 0; i < len(arr3); i++ {
|
||||
t.Log(arr3[i])
|
||||
}
|
||||
|
||||
for idx, v := range arr3 {
|
||||
t.Log(idx, v)
|
||||
}
|
||||
|
||||
for _, v := range arr3 {
|
||||
t.Log(v)
|
||||
}
|
||||
}
|
||||
|
||||
// 数组截断
|
||||
func TestArraySection(t *testing.T) {
|
||||
arr3 := [...]int{1, 2, 3, 4, 5}
|
||||
// 截取 arr[开始索引(包含), 结束索引(不包含)]
|
||||
arr3_sec := arr3[1:4]
|
||||
t.Log(arr3_sec) //2.3.4
|
||||
t.Log(arr3[1:]) //2,3,4,5
|
||||
t.Log(arr3[:3]) //1,2,3
|
||||
}
|
12
src/c6_loop/loop_test.go
Normal file
12
src/c6_loop/loop_test.go
Normal file
|
@ -0,0 +1,12 @@
|
|||
package loop_test
|
||||
|
||||
import "testing"
|
||||
|
||||
// for循环
|
||||
func TestWhileLoop(t *testing.T) {
|
||||
n := 0
|
||||
for n < 5 {
|
||||
t.Log(n)
|
||||
n++
|
||||
}
|
||||
}
|
51
src/c6_slice_test/slice_test.go
Normal file
51
src/c6_slice_test/slice_test.go
Normal file
|
@ -0,0 +1,51 @@
|
|||
package slice_test
|
||||
|
||||
import "testing"
|
||||
|
||||
// 切片定义
|
||||
func TestSlienceInit(t *testing.T) {
|
||||
var s0 []int
|
||||
t.Log(len(s0), cap(s0))
|
||||
s0 = append(s0, 1)
|
||||
t.Log(len(s0), cap(s0))
|
||||
|
||||
s1 := []int{1, 2, 3, 4}
|
||||
t.Log(len(s1), cap(s1))
|
||||
|
||||
s2 := make([]int, 3, 5)
|
||||
t.Log(len(s2), cap(s2))
|
||||
t.Log(s2[0], s2[1], s2[2])
|
||||
s2 = append(s2, 4)
|
||||
t.Log(len(s2), cap(s2))
|
||||
t.Log(s2[0], s2[1], s2[2], s2[3])
|
||||
}
|
||||
|
||||
// 切片增长演示
|
||||
func TestSliceGrowing(t *testing.T) {
|
||||
s := []int{}
|
||||
for i := 0; i < 10; i++ {
|
||||
s = append(s, i)
|
||||
t.Log(len(s), cap(s))
|
||||
}
|
||||
}
|
||||
|
||||
// 切片的共享内存 演示
|
||||
func TestSliceShareMemory(t *testing.T) {
|
||||
letter := []string{"a", "b", "c", "d", "e", "f", "g", "h", "i", "j", "k", "L"}
|
||||
letter2 := letter[3:6]
|
||||
t.Log(letter2, len(letter2), cap(letter2))
|
||||
l3 := letter[5:8]
|
||||
t.Log(l3, len(l3), cap(l3))
|
||||
l3[0] = "U"
|
||||
t.Log(letter2)
|
||||
t.Log(letter)
|
||||
}
|
||||
|
||||
// 切片不能比较
|
||||
func TestSliceCompare(t *testing.T) {
|
||||
// a := []int{1, 2, 3, 4}
|
||||
// b := []int{1, 2, 3, 4}
|
||||
// if a == b {
|
||||
// t.Log("equals")
|
||||
// }
|
||||
}
|
50
src/c7_map_test/map_test.go
Normal file
50
src/c7_map_test/map_test.go
Normal file
|
@ -0,0 +1,50 @@
|
|||
package map_test
|
||||
|
||||
import (
|
||||
"testing"
|
||||
)
|
||||
|
||||
// map的声明
|
||||
func TestMapInit(t *testing.T) {
|
||||
m1 := map[string]int{"a": 1, "b": 2, "c": 3}
|
||||
t.Log(m1["b"])
|
||||
t.Logf("len m1=%d", len(m1))
|
||||
|
||||
m2 := map[string]int{}
|
||||
m2["d"] = 4
|
||||
t.Logf("len m2=%d", len(m2))
|
||||
m3 := make(map[string]int, 10)
|
||||
t.Logf("len m3=%d", len(m3))
|
||||
}
|
||||
|
||||
// map判断键key是否存在
|
||||
func TestAccessNotExistingKey(t *testing.T) {
|
||||
m1 := map[int]int{}
|
||||
// 不存在会默认为0 而不是nil
|
||||
t.Log(m1[1])
|
||||
m1[2] = 0
|
||||
t.Log(m1[2])
|
||||
|
||||
if v, ok := m1[3]; ok {
|
||||
t.Logf("Key 3 value is %d", v)
|
||||
} else {
|
||||
t.Log("Key 3 is not exist")
|
||||
}
|
||||
|
||||
// 赋值后
|
||||
m1[3] = 0
|
||||
if v, ok := m1[3]; ok {
|
||||
t.Logf("Key 3 value is %d", v)
|
||||
} else {
|
||||
t.Log("Key 3 is not exist")
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// 遍历Map
|
||||
func TestTravelMap(t *testing.T) {
|
||||
m1 := map[string]int{"a": 1, "b": 2, "c": 3}
|
||||
for k, v := range m1 {
|
||||
t.Logf("Key: %s, Value: %d", k, v)
|
||||
}
|
||||
}
|
48
src/c8_map_ext/map_ext_test.go
Normal file
48
src/c8_map_ext/map_ext_test.go
Normal file
|
@ -0,0 +1,48 @@
|
|||
package map_ext
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"testing"
|
||||
)
|
||||
|
||||
// 值为方法的map
|
||||
func TestMapWithFunValue(t *testing.T) {
|
||||
m := map[int]func(op int) int{}
|
||||
m[1] = func(op int) int { return op }
|
||||
m[2] = func(op int) int { return op * op }
|
||||
m[3] = func(op int) int { return op + op + op }
|
||||
t.Log(m[1](2), m[2](2), m[3](2))
|
||||
}
|
||||
|
||||
// Map实现Set操作
|
||||
func TestMapForSet(t *testing.T) {
|
||||
mySet := map[int]bool{}
|
||||
|
||||
// 添加元素
|
||||
mySet[1] = true
|
||||
mySet[2] = false
|
||||
t.Logf("set len=%d", len(mySet))
|
||||
|
||||
// 判断元素是否存在
|
||||
n := 3
|
||||
if mySet[n] {
|
||||
t.Logf("%d is exist", n)
|
||||
} else {
|
||||
t.Logf("%d is not exist", n)
|
||||
}
|
||||
|
||||
//删除元素
|
||||
delete(mySet, 1)
|
||||
ValueIsExit(mySet, 1)
|
||||
|
||||
}
|
||||
|
||||
func ValueIsExit(s map[int]bool, v int) bool {
|
||||
if s[v] {
|
||||
fmt.Printf("%d is exist", v)
|
||||
return true
|
||||
} else {
|
||||
fmt.Printf("%d is not exist", v)
|
||||
return false
|
||||
}
|
||||
}
|
31
src/c9_string/string_func_test.go
Normal file
31
src/c9_string/string_func_test.go
Normal file
|
@ -0,0 +1,31 @@
|
|||
package string_test
|
||||
|
||||
import (
|
||||
"strconv"
|
||||
"strings"
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestStringFn(t *testing.T) {
|
||||
s := "A,B,C"
|
||||
// 切割
|
||||
parts := strings.Split(s, ",")
|
||||
for _, v := range parts {
|
||||
t.Log(v)
|
||||
}
|
||||
|
||||
// 连接
|
||||
t.Log(strings.Join(parts, "-"))
|
||||
}
|
||||
|
||||
func TestStrConv(t *testing.T) {
|
||||
// int to string
|
||||
s := strconv.Itoa(10)
|
||||
t.Log(s)
|
||||
|
||||
// string to int
|
||||
if i, err := strconv.Atoi("10"); err == nil {
|
||||
t.Log(10 + i)
|
||||
}
|
||||
|
||||
}
|
29
src/c9_string/string_test.go
Normal file
29
src/c9_string/string_test.go
Normal file
|
@ -0,0 +1,29 @@
|
|||
package string_test
|
||||
|
||||
import "testing"
|
||||
|
||||
func TestString(t *testing.T) {
|
||||
var s string
|
||||
t.Log(s) //初始化值为空字符串 ""
|
||||
s = "hello"
|
||||
t.Log(len(s))
|
||||
|
||||
s = "\xE4\xB8\xA5" // 可以存储任何二进制数据
|
||||
// s = "\xE4\xBA\xB5\xFF"
|
||||
t.Log(s)
|
||||
|
||||
s = "中"
|
||||
t.Log(len(s)) // 是byte数
|
||||
|
||||
c := []rune(s)
|
||||
t.Log(len(c))
|
||||
t.Logf("中 unicode %x", c[0])
|
||||
t.Logf("中 UTF8 %x", s)
|
||||
}
|
||||
|
||||
func TestStringToRune(t *testing.T) {
|
||||
s := "中华人民共和国"
|
||||
for _, c := range s {
|
||||
t.Logf("%[1]c %[1]d, %[1]x", c)
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue
Block a user