24.变量内置的pair
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
}