Golang基础语法(5)

401 阅读3分钟

24.变量内置的pair

image-20230105175507769

pair数据结构(type+value)


var a string
//pair<type:string,value:"123">
a="123"

var s string
//此时赋值,那么s的pair就为a的pair,通过赋值进行不断延续
s=a

2.反射 reflect包

  • ValueOf

用来获取输入参数接口的数据值,接口为空则返回0

  • TypeOf

用来动态获取输入参数接口中值的类型,如果接口为空 返回nil

package main

import (
	"fmt"
	"reflect"
)

func reflectNum(arg interface{}) {
	fmt.Print("type: ", reflect.TypeOf(arg))
	fmt.Print("value: ", reflect.ValueOf(arg))

}
func main() {
	var num float64 = 1.242
	reflectNum(num)
    /*
    type: float64 value: 1.242
    */

}

反射获取参数值

package main

import (
	"fmt"
	"reflect"
)

type User struct {
	Id   int
	Name string
	Age  int
}

func (this User) Call() {
	fmt.Print("user is called")
	fmt.Printf("%v", this)
}
//通过type获得里面的字段
func reflectNum(arg interface{}) {
	argType := reflect.TypeOf(arg)
	argValue := reflect.ValueOf(arg)
	for i := 0; i < argType.NumField(); i++ {
		field := argType.Field(i)
		numField := argValue.Field(i).Interface()
		fmt.Printf("%s: %v=%v\n", field.Name, field.Type, numField)
	}
    
    //通过type获得里面的方法
	for i := 0; i < argType.NumMethod(); i++ {
		method := argType.Method(i)
		fmt.Printf("%s %v", method.Name, method.Type)
	}

}
func main() {
	user := User{Id: 1, Name: "123", Age: 18}
	reflectNum(user)

}

3.结构体标签

package main

import (
	"fmt"
	"reflect"
)

type Book struct {
	auth string `info:"Name" doc:"我的名字"`
}

func findTage(arg interface{}) {
	t := reflect.TypeOf(arg).Elem()
	for i := 0; i < t.NumField(); i++ {
		myTag := t.Field(i).Tag.Get("info")
		fmt.Print(myTag)
	}
}
func main() {
	var s Book
    //因为上方使用了Elem所以传入地址,也可以不用Elem,下方不传地址
	findTage(&s)
}

可以看到 对于 Type类型的funcTyp,直接取Kind时,它的类型为ptr,也就是在反射中所有的指针类型都是ptr,但是当我们想要获取指针背后元素的真正数据类型时就需要使用Elem方法

Golang中的reflect.Elem()函数用于获取接口v包含的值或指针v指向的值

4.结构体标签在json中的使用

package main

import (
	"encoding/json"
	"fmt"
)

type Person struct {
    //字段必须首字母大写
    //
	Name string `json:"name"`
	Age  string `json:"age"`
	Sex  string `json:"sex"`
}

func main() {
	person := Person{Name: "hello", Age: "18", Sex: "男"}
	//将结构体转换为json
	marshal, err := json.Marshal(person)
	if err == nil {
		fmt.Printf("%s", marshal)
	} else {
		fmt.Print("失败")
	}
	//json字符串转结构体
	jsonstr := Person{}
	err = json.Unmarshal(marshal, &jsonstr)
	if err != nil {
		fmt.Print("unmarshal is erro")
	}
	fmt.Printf("%v\n", jsonstr)
}

从上面代码可以看出如果结构体的字段首字母小写,该字段将无法正常解析

25.闭包

闭包就是能够读取其他函数内部变量的函数。

所以说,闭包可以简单理解成“定义在一个函数内部的函数。

所以,在本质上,闭包是将函数内部和函数外部连接起来的桥梁。

package main

import (
    "fmt"
)

func a() func() int {
    i := 0
    b := func() int {
        i++
        fmt.Println(i)
        return i
    }
    return b
}

func main() {
    c := a()
    c()
    c()
    c()

    a() //不会输出i
}
/*
1
2
3
*/

闭包复制的是原对象指针,这就很容易解释延迟引用现象。

package main

import "fmt"

func test() func() {
    x := 100
    fmt.Printf("x (%p) = %d\n", &x, x)

    return func() {
        fmt.Printf("x (%p) = %d\n", &x, x)
    }
}

func main() {
    f := test()
    f()
}
/*
    x (0xc42007c008) = 100
    x (0xc42007c008) = 100
    */

外部引用函数参数局部变量

package main

import "fmt"

// 外部引用函数参数局部变量
func add(base int) func(int) int {
    return func(i int) int {
        base += i
        return base
    }
}

func main() {
    tmp1 := add(10)
    fmt.Println(tmp1(1), tmp1(2)) //11,13
    // 此时tmp1和tmp2不是一个实体了
    tmp2 := add(100)
    fmt.Println(tmp2(1), tmp2(2)) //101,103
}

返回两个闭包

package main

import "fmt"

// 返回2个函数类型的返回值
func test01(base int) (func(int) int, func(int) int) {
	// 定义2个函数,并返回
	// 相加
	add := func(i int) int {
		base += i
		return base
	}
	// 相减
	sub := func(i int) int {
		base -= i
		return base
	}
	// 返回
	return add, sub
}

func main() {
	f1, f2 := test01(10)
	// base一直是没有消
	fmt.Println(f1(1), f2(2))//11 9
	// 此时base是9
	fmt.Println(f1(3), f2(4))//12 8
}