2176 字
11 分钟
01、

01、#

// 反射
type student struct {
Name string `json:"name"`
Age int `json:"age"`
}
func main() {
str := `{"name":"周林","age":9000}`
var stu1 student
json.Unmarshal([]byte(str), &stu1)
fmt.Printf("%#v\n", stu1)
}

02、#

// strconv
func main() {
// 从字符串中解析出对应的数据
str := "10000"
// ret1 := int64(str)
ret1, err := strconv.ParseInt(str, 10, 64)
if err != nil {
fmt.Println("parseint failed, err:", err)
return
}
fmt.Printf("%#v %T\n", ret1, int(ret1))
// Atoi:字符串转换成int
retInt, _ := strconv.Atoi(str)
fmt.Printf("%#v %T\n", retInt, retInt)
// 从字符串中解析出布尔值
boolStr := "true"
boolValue, _ := strconv.ParseBool(boolStr)
fmt.Printf("%#v %T\n", boolValue, boolValue)
// 从字符串中解析出浮点数
floatStr := "1.234"
floatValue, _ := strconv.ParseFloat(floatStr, 64)
fmt.Printf("%#v %T\n", floatValue, floatValue)
// 把数字转换成字符串类型
i := 97
// ret2 := string(i) // "a"
ret2 := fmt.Sprintf("%d", i) // "97"
fmt.Printf("%#v", ret2)
ret3 := strconv.Itoa(i)
fmt.Printf("%#v", ret3)
}

03、#

// goroutine
func hello(i int) {
fmt.Println("hello", i)
}
// 程序启动之后会创建一个主goroutine去执行
func main() {
for i := 0; i < 1000; i++ {
// go hello(i) // 开启一个单独的goroutine去执行hello函数(任务)
go func(i int) {
fmt.Println(i) // 用的是函数参数的那个i,不是外面的i
}(i)
}
fmt.Println("main")
time.Sleep(time.Second)
// main函数结束了 由main函数启动的goroutine也都结束了
}

04、#

// waitGroup
func f() {
rand.Seed(time.Now().UnixNano())
for i := 0; i < 5; i++ {
r1 := rand.Int() // int64
r2 := rand.Intn(10) // 0<= x < 10
fmt.Println(0-r1, 0-r2)
}
}
func f1(i int) {
defer wg.Done()
time.Sleep(time.Second * time.Duration(rand.Intn(3)))
fmt.Println(i)
}
var wg sync.WaitGroup
func main() {
// f()
// wg.Add(10)
for i := 0; i < 10; i++ {
wg.Add(1)
go f1(i)
}
// ?如何知道这10个goroutine都结束了
// time.Sleep(?)
wg.Wait() // 等待wg的计数器减为0
}

05、#

// GOMAXPROCS
var wg sync.WaitGroup
func a() {
defer wg.Done()
for i := 0; i < 10; i++ {
fmt.Printf("A:%d\n", i)
}
}
func b() {
defer wg.Done()
for i := 0; i < 10; i++ {
fmt.Printf("B:%d\n", i)
}
}
func main() {
runtime.GOMAXPROCS(1) // 默认CPU的逻辑核心数,默认跑满整个CPU
fmt.Println(runtime.NumCPU())
wg.Add(2)
go a()
go b()
}

06、#

var a []int
var b chan int // 需要指定通道中元素的类型
var wg sync.WaitGroup
func noBufChannel() {
fmt.Println(b) // nil
b = make(chan int) // 不带缓冲区通道的初始化
wg.Add(1)
go func() {
defer wg.Done()
x := <-b
fmt.Println("后台goroutine从通道b中取到了", x)
}()
b <- 10 // hang住了
fmt.Println("10发送到通道b中了...")
wg.Wait()
}
func bufChannel() {
fmt.Println(b) // nil
b = make(chan int, 10) // 不带缓冲区通道的初始化
b <- 10 // hang住了
fmt.Println("10发送到通道b中了...")
b <- 20
fmt.Println("20发送到通道b中了...")
x := <-b
fmt.Println("从通道b中取到了", x)
close(b)
}
func main() {
bufChannel()
}

07、#

// channel练习
// 1. 启动一个goroutine,生成100个数发送到ch1
// 2. 启动一个goroutine,从ch1中取值,计算其平方放到ch2中
// 3. 在main中 从ch2取值打印出来
var wg sync.WaitGroup
var once sync.Once
func f1(ch1 chan<- int) {
defer wg.Done()
for i := 0; i < 100; i++ {
ch1 <- i
}
close(ch1)
}
func f2(ch1 <-chan int, ch2 chan<- int) {
defer wg.Done()
for {
x, ok := <-ch1
if !ok {
break
}
ch2 <- x * x
}
once.Do(func() { close(ch2) }) // 确保某个操作只执行一次
}
func main() {
a := make(chan int, 100)
b := make(chan int, 100)
wg.Add(3)
go f1(a)
go f2(a, b)
go f2(a, b)
wg.Wait()
for ret := range b {
fmt.Println(ret)
}
}

08、#

// 关闭通道
func main() {
ch1 := make(chan bool, 2)
ch1 <- true
ch1 <- true
close(ch1)
// for x := range ch1 {
// fmt.Println(x)
// }
<-ch1
<-ch1
x, ok := <-ch1
fmt.Println(x, ok)
x, ok = <-ch1
fmt.Println(x, ok)
x, ok = <-ch1
fmt.Println(x, ok)
}

09、#

func worker(id int, jobs <-chan int, results chan<- int) {
for j := range jobs {
fmt.Printf("worker:%d start job:%d\n", id, j)
time.Sleep(time.Second)
fmt.Printf("worker:%d end job:%d\n", id, j)
results <- j * 2
}
}
func main() {
jobs := make(chan int, 100)
results := make(chan int, 100)
// 开启3个goroutine
for w := 1; w <= 3; w++ {
go worker(w, jobs, results)
}
// 5个任务
for j := 1; j <= 5; j++ {
jobs <- j
}
close(jobs)
// 输出结果
for a := 1; a <= 5; a++ {
<-results
}
}

10、#

/*
使用goroutine和channel实现一个计算int64随机数各位数和的程序。
1. 开启一个goroutine循环生成int64类型的随机数,发送到jobChan
2. 开启24个goroutine从jobChan中取出随机数计算各位数的和,将结果发送到resultChan
3. 主goroutine从resultChan取出结果并打印到终端输出
*/
// job ...
type job struct {
value int64
}
// Result ...
type result struct {
job *job
sum int64
}
var jobChan = make(chan *job, 100)
var resultChan = make(chan *result, 100)
var wg sync.WaitGroup
func zhoulin(zl chan<- *job) {
defer wg.Done()
// 循环生成int64类型的随机数,发送到jobChan
for {
x := rand.Int63()
newJob := &job{
value: x,
}
zl <- newJob
time.Sleep(time.Millisecond * 500)
}
}
func baodelu(zl <-chan *job, resultChan chan<- *result) {
defer wg.Done()
// 从jobChan中取出随机数计算各位数的和,将结果发送到resultChan
for {
job := <-zl
sum := int64(0)
n := job.value
for n > 0 {
sum += n % 10
n = n / 10
}
newResult := &result{
job: job,
sum: sum,
}
resultChan <- newResult
}
}
func main() {
wg.Add(1)
go zhoulin(jobChan)
// 开启24个goroutine执行保德路
wg.Add(24)
for i := 0; i < 24; i++ {
go baodelu(jobChan, resultChan)
}
// 主goroutine从resultChan取出结果并打印到终端输出
for result := range resultChan {
fmt.Printf("value:%d sum:%d\n", result.job.value, result.sum)
}
wg.Wait()
}

11、#

// select
func main() {
ch := make(chan int, 10)
for i := 0; i < 10; i++ {
select {
case x := <-ch:
fmt.Println(x)
case ch <- i:
}
}
}

12、ini_demo 配置文件解析#

// ini配置文件解析器
// MysqlConfig MySQL配置结构体
type MysqlConfig struct {
Address string `ini:"address"`
Port int `ini:"port"`
Username string `ini:"username"`
Password string `ini:"password"`
}
// RedisConfig ...
type RedisConfig struct {
Host string `ini:"host"`
Port int `ini:"port"`
Password string `ini:"password"`
Database int `ini:"database"`
Test bool `ini:"test"`
}
// Config ...
type Config struct {
MysqlConfig `ini:"mysql"`
RedisConfig `ini:"redis"`
}
// 尽量去掌握
func loadIni(fileName string, data interface{}) (err error) {
// 0. 参数的校验
// 0.1 传进来的data参数必须是指针类型(因为需要在函数中对其赋值)
t := reflect.TypeOf(data)
fmt.Println(t, t.Kind())
if t.Kind() != reflect.Ptr {
err = errors.New("data param should be a pointer") // 新创建一个错误
return
}
// 0.2 传进来的data参数必须是结构体类型指针(因为配置文件中各种键值对需要赋值给结构体的字段)
if t.Elem().Kind() != reflect.Struct {
err = errors.New("data param should be a struct pointer") // 新创建一个错误
return
}
// 1. 读文件得到字节类型数据
b, err := ioutil.ReadFile(fileName)
if err != nil {
return
}
// string(b) // 将字节类型的文件内容转换成字符串
lineSlice := strings.Split(string(b), "\r\n")
// fmt.Printf("%#v\n", lineSlice)
// 2. 一行一行得读数据
var structName string
for idx, line := range lineSlice {
// 去掉字符串首尾的空格
line = strings.TrimSpace(line)
// 如果是空行就跳过
if len(line) == 0 {
continue
}
// 2.1 如果是注释就跳过
if strings.HasPrefix(line, ";") || strings.HasPrefix(line, "#") {
continue
}
// 2.2 如果是[开头的就表示是节(section)
if strings.HasPrefix(line, "[") {
if line[0] != '[' || line[len(line)-1] != ']' {
err = fmt.Errorf("line:%d syntax error", idx+1)
return
}
// 把这一行首尾的[]去掉,取到中间的内容把首尾的空格去掉拿到内容
sectionName := strings.TrimSpace(line[1 : len(line)-1])
if len(sectionName) == 0 {
err = fmt.Errorf("line:%d syntax error", idx+1)
return
}
// 根据字符串sectionName去data里面根据反射找到对应的结构体
for i := 0; i < t.Elem().NumField(); i++ {
field := t.Elem().Field(i)
if sectionName == field.Tag.Get("ini") {
// 说明找到了对应的嵌套结构体,把字段名记下来
structName = field.Name
fmt.Printf("找到%s对应的嵌套结构体%s\n", sectionName, structName)
}
}
} else {
// 2.3 如果不是[开头就是=分割的键值对
// 1. 以等号分割这一行,等号左边是key,等号右边是value
if strings.Index(line, "=") == -1 || strings.HasPrefix(line, "=") {
err = fmt.Errorf("line:%d syntax error", idx+1)
return
}
index := strings.Index(line, "=")
key := strings.TrimSpace(line[:index])
value := strings.TrimSpace(line[index+1:])
// 2. 根据strucrName 去 data 里面把对应的嵌套结构体给取出来
v := reflect.ValueOf(data)
sValue := v.Elem().FieldByName(structName) // 拿到嵌套结构体的值信息
sType := sValue.Type() // 拿到嵌套结构体的类型信息
if sType.Kind() != reflect.Struct {
err = fmt.Errorf("data中的%s字段应该是一个结构体", structName)
return
}
var fieldName string
var fileType reflect.StructField
// 3. 遍历嵌套结构体的每一个字段,判断tag是不是等于key
for i := 0; i < sValue.NumField(); i++ {
filed := sType.Field(i) // tag信息是存储在类型信息中的
if filed.Tag.Get("ini") == key {
// 找到对应的字段
fieldName = filed.Name
fileType = filed
break
}
}
// 4. 如果key = tag,给这个字段赋值
// 4.1 根据fieldName 去取出这个字段
if len(fieldName) == 0 {
// 在结构体中找不到对应的字符
continue
}
fileObj := sValue.FieldByName(fieldName)
// 4.2 对其赋值
fmt.Println(fieldName, fileType.Type.Kind())
switch fileType.Type.Kind() {
case reflect.String:
fileObj.SetString(value)
case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
var valueInt int64
valueInt, err = strconv.ParseInt(value, 10, 64)
if err != nil {
err = fmt.Errorf("line:%d value type error", idx+1)
return
}
fileObj.SetInt(valueInt)
case reflect.Bool:
var valueBool bool
valueBool, err = strconv.ParseBool(value)
if err != nil {
err = fmt.Errorf("line:%d value type error", idx+1)
return
}
fileObj.SetBool(valueBool)
case reflect.Float32, reflect.Float64:
var valueFloat float64
valueFloat, err = strconv.ParseFloat(value, 64)
if err != nil {
err = fmt.Errorf("line:%d value type error", idx+1)
return
}
fileObj.SetFloat(valueFloat)
}
}
}
return
}
func main() {
var cfg Config
err := loadIni("./conf.ini", &cfg)
if err != nil {
fmt.Printf("load ini failed, err:%v\n", err)
return
}
fmt.Printf("%#v\n", cfg)
}

conf.init 文件#

; mysql config
[mysql]
address=10.20.30.40
port=3306
username=root
password=rootroot
# redis config
; [
; [ ]
[redis]
; heihei
; = hahaha
xxx=
host =11.22.33.44
port=6379
password=root123
database=0
test=false
01、
https://blog.zhequtao.com/posts/golang/go-new/base/base07/
作者
阿俊
发布于
2020-03-30
许可协议
CC BY-NC-SA 4.0

相关阅读