diff --git a/dailylib/gojsonq/datasource/data.json b/dailylib/gojsonq/datasource/data.json new file mode 100644 index 0000000000000000000000000000000000000000..732082b66dd1954f02ea3f4d54ba0a75b29db82d --- /dev/null +++ b/dailylib/gojsonq/datasource/data.json @@ -0,0 +1,37 @@ +{ + "name": "shopping cart", + "description": "List of items in your cart", + "prices": ["2400", "2100", "1200", "400.87", "89.90", "150.10"], + "items": [ + { + "id": 1, + "name": "Apple", + "count": 2, + "price": 12 + }, + { + "id": 2, + "name": "Notebook", + "count": 10, + "price": 3 + }, + { + "id": 3, + "name": "Pencil", + "count": 5, + "price": 1 + }, + { + "id": 4, + "name": "Camera", + "count": 1, + "price": 1750 + }, + { + "id": null, + "name": "Invalid Item", + "count": 1, + "price": 12000 + } + ] +} \ No newline at end of file diff --git a/dailylib/gojsonq/datasource/main.go b/dailylib/gojsonq/datasource/main.go new file mode 100644 index 0000000000000000000000000000000000000000..c1e9d8a99d1c0cec4eaa47f03bb7ee4eac301f9f --- /dev/null +++ b/dailylib/gojsonq/datasource/main.go @@ -0,0 +1,109 @@ +package main + +import ( + "encoding/json" + "fmt" + "github.com/thedevsaddam/gojsonq" + "os" +) + +/* +1.路径问题 + 注意, 在go项目中./ 表示的并不是当前路径,而是工程路径,例如当前工程为GopherUtils则.表示GopherUtils/ + 所以data.json文件的相对路径为: "./dailylib/gojsonq/datasource/data.json" + +2.gojsonq.New()的三种读取方式 + 2.1 FromString() 从json字符串读取 + 2.2 File 从文件读取 + 2.3 Reader 从io.Reader对象中读取 + +3.Select操作 + r := gojsonq.New().From("items").Select("id", "name").Get() + 3.1 From是将当前节点位置移动到指定位置上,例如From("items")即为将当前位置移动到items节点处,后续的操作均是对items这个列表进行操作 + 3.1 Select指定返回哪些字段,例如:items : [{"a":1, "b":2}, {"a":2, "b":3}];可以把items列表中的每一个字典看作一条一条数据, + select则是将每一条数据的指定字段取出来: select a from items + Get()会组合所有条件然后执行该查询,返回结果: [{"a":1}, {"a":2}] + +4.json.MarshalIndent(v interface{}, prefix string, indent string) ([]byte, error) + 将数据转换为json字符串,并对格式进行美化,每一个json元素都会单独占一行,prefix为每一行添加一个前缀,index为缩进空格数 + 返回一个字节数组,如果需要打印,可以将其转换为字符串string(data) + +5.Where查询 + 5.1 Where默认是and查询,Where需要传递三个参数,第一个是字段名,第二个是关系,第三个是值,例如Where("count", ">", 1)即表示 + where count > 1; + 5.2 OrWhere 也需要传入三个参数,与Where一致,表示or查询 + 5.3 WhereIn(key, val)与Where(key, "in", val)等效,WhereStartsWith(key, val)与 Where(key, "startsWith", val)等效 + +6.Offset-Limit + Offset表示偏移量 + Limit表示返回的条目数 + + 设置Offset和Limit时,首先明确一页数据量有多少(假设为n),则如果要查看第i页的所有数据,Offset = (i-1)*n Limit=n + +7.聚合 + 7.1 注意:聚合操作不会修改当前节点指向 + 7.2 gq.Sum("count") 就相当于 sum(count) gq.Count() gq.Max() gq.Min() + 7.3 分组,排序: gq.GroupBy("price").Get() gq.SortBy("price", "desc").Get() + + +*/ + +func main() { + // 1.直接从文件读取 + path := "./dailylib/gojsonq/datasource/data.json" + gq := gojsonq.New().File(path) + res := gq.Find("items.[1].price") + fmt.Println(res) + + // 2.从io.Reader对象中读取 + //file, err := os.OpenFile(path, os.O_RDONLY, 0666) + // path中.表示的当前的工程路径,即GopherUtils/ + file, err := os.OpenFile(path, os.O_RDONLY, 0666) + if err != nil { + fmt.Println(err) + return + } + gq1 := gojsonq.New().Reader(file) + res1 := gq1.Find("items.[0].price") + fmt.Println(res1) + + // 二、select查询 + r := gojsonq.New().File(path).From("items").Select("id", "name").Get() + data, _ := json.MarshalIndent(r, "", " ") + fmt.Println(string(data)) + + // 三、where查询 + // select id, name from items where id =1 or id =2 + gq2 := gojsonq.New().File(path) + r2 := gq2.From("items").Select("id", "name"). + Where("id", "=", 1).OrWhere("id", "=", 2).Get() + fmt.Println(r2) + + gq2.Reset() + + // select id, name from items where count > 1 and price < 100 + r2 = gq2.From("items").Select("id", "name"). + Where("count", ">", 1).Where("price", "<", 100).Get() + fmt.Println(r2) + + // 四、Offset-Limit + gq3 := gojsonq.New().File(path) + r3 := gq3.From("items").Select("id", "name").Offset(0).Limit(3).Get() + fmt.Println("First Page: ", r3) + + gq3.Reset() + + r3 = gq3.From("items").Select("id", "name").Offset(3).Limit(3).Get() + fmt.Println("Second Page: ", r3) + + // 五、聚合,分组,排序 + gq4 := gojsonq.New().File(path).From("items") + fmt.Println("Total Count: ", gq4.Sum("count")) + fmt.Println("Min Price: ", gq4.Min("price")) + fmt.Println("Max price", gq4.Max("price")) + fmt.Println("Avg price", gq4.Avg("price")) + + fmt.Println(gq4.GroupBy("price").Get()) + gq4.Reset() + fmt.Println(gq4.SortBy("price", "desc").Get()) +} diff --git a/dailylib/gojsonq/get-started/main.go b/dailylib/gojsonq/get-started/main.go new file mode 100644 index 0000000000000000000000000000000000000000..cc7eea86082165562038882e22ad0a104178b359 --- /dev/null +++ b/dailylib/gojsonq/get-started/main.go @@ -0,0 +1,48 @@ +package main + +import ( + "fmt" + "github.com/thedevsaddam/gojsonq" +) + +/* +1.go get时出现:SSL certificate problem: certificate has expired + 将rsa.pub里面的密钥重新复制,然后删除github上的ssh key,新建一个ssh key实例,将之前复制的rsa.pub中的信息复制到其中,然后重启goland + go get -u -v github.com/thedevsaddam/gojsonq + +2.gojsonq基本用法 + 2.1 gojsonq.New()返回一个*JSONQ对象,gojsonq.New().FromString(content)将json字符串转换为一个*JSONQ对象 + 2.2 gq.Find("user.address.district") 如果是嵌套map,用.获取下一次的键值,如果是slice, + 用[n]来获取第n个元素(gq.Find("user.address.hobbies[0]")) + 2.3 注意:当用gq.Find()查找到某一节点后,下一次再查找是从上一次查找到的节点作为根节点继续查找: + 例如先使用gq.Find("user.address.provice")查找后,下一次再查找就是从provice节点开始查找, + 所以gq.Find("user.hobbies.[0]")是无法查找到的,所以会返回nil + 2.4 gq.Reset() 会将gq对象重置到初始状态下;也可以使用gpCopy := gq.Copy() 返回一个初始状态下的gq对象 + +3.异常返回nil + 如果content不是一个合法的json字符串,则gojsonq解析后获取到的数据均是nil(可以使用json.Unmarshal()对json字符串进行解析,看是否错误) +*/ + +func main() { + content := `{ + "user": { + "name": "dj", + "age": 18, + "address": { + "provice": "shanghai", + "district": "xuhui" + }, + "hobbies": ["chess", "programming", "game"] + } +}` + + gq := gojsonq.New().FromString(content) + district := gq.Find("user.address.district") + fmt.Println(district) + + // 可以替换为gqCopy := gq.Copy(),返回一个初始状态下的*JSONQ,然后对gqCopy进行操作即可 + gq.Reset() + + hobby := gq.Find("user.hobbies.[0]") + fmt.Println(hobby) +} diff --git a/dailylib/gojsonq/yaml/data.yaml b/dailylib/gojsonq/yaml/data.yaml new file mode 100644 index 0000000000000000000000000000000000000000..ea600ec2a2eb4df34a0c8b8976e9410309e7d226 --- /dev/null +++ b/dailylib/gojsonq/yaml/data.yaml @@ -0,0 +1,30 @@ +description: List of items in your cart +items: +- count: 2 + id: 1 + name: Apple + price: 12 +- count: 10 + id: 2 + name: Notebook + price: 3 +- count: 5 + id: 3 + name: Pencil + price: 1 +- count: 1 + id: 4 + name: Camera + price: 1750 +- count: 1 + id: null + name: Invalid Item + price: 12000 +name: shopping cart +prices: +- "2400" +- "2100" +- "1200" +- "400.87" +- "89.90" +- "150.10" diff --git a/dailylib/gojsonq/yaml/main.go b/dailylib/gojsonq/yaml/main.go new file mode 100644 index 0000000000000000000000000000000000000000..5484d228cb6b77ceee87ffca0bad2a70e11fa9a7 --- /dev/null +++ b/dailylib/gojsonq/yaml/main.go @@ -0,0 +1,33 @@ +package main + +import ( + "encoding/json" + "fmt" + "github.com/ghodss/yaml" + "github.com/thedevsaddam/gojsonq" +) + +/* +1.自定义解析格式 + 只需要实现了Decode(data []byte, v interface{}) error {} 接口,即可传入gojsonq.SetDecoder中作为解析器,解析任意格式数据 + 不同格式的数据只是解析方式改变,但像Where等的查询使用方式不变 +*/ + +type yamlDecoder struct{} + +func (i *yamlDecoder) Decode(data []byte, v interface{}) error { + // 将yaml数据解析成json格式数据 + bb, err := yaml.YAMLToJSON(data) + if err != nil { + return err + } + return json.Unmarshal(bb, &v) +} + +func main() { + path := "./dailylib/gojsonq/yaml/data.yaml" + jq := gojsonq.New(gojsonq.SetDecoder(&yamlDecoder{})).File(path) + jq.From("items").Where("price", "<=", 500) + // 返回第一个元素,items是一个包含多个字段的列表,所以First会返回第一个字典 + fmt.Printf("%v\n", jq.First()) +} diff --git a/subscriptions/5.31-6.6/reflect/basic/main.go b/subscriptions/5.31-6.6/reflect/basic/main.go index ea1ecee05405cad0eccd8c0a8d50e338f8021554..52d9c20fef62c7a6e851398fec4ba76aac15b56e 100644 --- a/subscriptions/5.31-6.6/reflect/basic/main.go +++ b/subscriptions/5.31-6.6/reflect/basic/main.go @@ -1,73 +1,73 @@ -package main - -import ( - "fmt" - "reflect" -) - -/* -一共 26 种,我们可以分类如下: - -基础类型Bool、String以及各种数值类型(有符号整数Int/Int8/Int16/Int32/Int64,无符号整数Uint/Uint8/Uint16/Uint32/Uint64/Uintptr,浮点数Float32/Float64,复数Complex64/Complex128) -复合(聚合)类型Array和Struct -引用类型Chan、Func、Ptr、Slice和Map(值类型和引用类型区分不明显,这里不引战,大家理解意思就行) -接口类型Interface -非法类型Invalid,表示它还没有任何值(reflect.Value的零值就是Invalid类型) -Go 中所有的类型(包括自定义的类型),都是上面这些类型或它们的组合。 - -const ( - Invalid Kind = iota - Bool - Int - Int8 - Int16 - Int32 - Int64 - Uint - Uint8 - Uint16 - Uint32 - Uint64 - Uintptr - Float32 - Float64 - Complex64 - Complex128 - Array - Chan - Func - Interface - Map - Ptr - Slice - String - Struct - UnsafePointer -) - */ - -type Cat struct { - Name string -} - -func main() { - // Go 语言是静态类型的,每个变量在编译期有且只能有一个确定的、已知的类型,即变量的静态类型。静态类型在变量声明的时候就已经确定了,无法修改。 - // 一个接口变量,它的静态类型就是该接口类型。虽然在运行时可以将不同类型的值赋值给它,改变的也只是它内部的动态类型和动态值。它的静态类型始终没有改变。 - var f float64 = 3.5 - c := Cat{Name: "kitty"} - - // TypeOf和ValueOf接收一个interface{} (空接口)值作为参数,如果传入的不是一个interface类型,则会先转换为接口类型 - t1 := reflect.TypeOf(f) - t2 := reflect.TypeOf(c) - fmt.Println(t1.String()) - fmt.Println(t2.String()) - - // fmt.Println会对reflect.Value做额外处理,获取其内部值 - // Go 语言中类型是无限的,而且可以通过type定义新的类型。但是类型的种类是有限的,reflect包中定义了所有种类的枚举: - v1 := reflect.ValueOf(f) - v2 := reflect.ValueOf(c) - fmt.Println(v1) - fmt.Println(v1.String()) - fmt.Println(v2) - fmt.Println(v2.String()) -} +package main + +import ( + "fmt" + "reflect" +) + +/* +一共 26 种,我们可以分类如下: + +基础类型Bool、String以及各种数值类型(有符号整数Int/Int8/Int16/Int32/Int64,无符号整数Uint/Uint8/Uint16/Uint32/Uint64/Uintptr,浮点数Float32/Float64,复数Complex64/Complex128) +复合(聚合)类型Array和Struct +引用类型Chan、Func、Ptr、Slice和Map(值类型和引用类型区分不明显,这里不引战,大家理解意思就行) +接口类型Interface +非法类型Invalid,表示它还没有任何值(reflect.Value的零值就是Invalid类型) +Go 中所有的类型(包括自定义的类型),都是上面这些类型或它们的组合。 + +const ( + Invalid Kind = iota + Bool + Int + Int8 + Int16 + Int32 + Int64 + Uint + Uint8 + Uint16 + Uint32 + Uint64 + Uintptr + Float32 + Float64 + Complex64 + Complex128 + Array + Chan + Func + Interface + Map + Ptr + Slice + String + Struct + UnsafePointer +) + */ + +type Cat struct { + Name string +} + +func main() { + // Go 语言是静态类型的,每个变量在编译期有且只能有一个确定的、已知的类型,即变量的静态类型。静态类型在变量声明的时候就已经确定了,无法修改。 + // 一个接口变量,它的静态类型就是该接口类型。虽然在运行时可以将不同类型的值赋值给它,改变的也只是它内部的动态类型和动态值。它的静态类型始终没有改变。 + var f float64 = 3.5 + c := Cat{Name: "kitty"} + + // TypeOf和ValueOf接收一个interface{} (空接口)值作为参数,如果传入的不是一个interface类型,则会先转换为接口类型 + t1 := reflect.TypeOf(f) + t2 := reflect.TypeOf(c) + fmt.Println(t1.String()) + fmt.Println(t2.String()) + + // fmt.Println会对reflect.Value做额外处理,获取其内部值 + // Go 语言中类型是无限的,而且可以通过type定义新的类型。但是类型的种类是有限的,reflect包中定义了所有种类的枚举: + v1 := reflect.ValueOf(f) + v2 := reflect.ValueOf(c) + fmt.Println(v1) + fmt.Println(v1.String()) + fmt.Println(v2) + fmt.Println(v2.String()) +} diff --git a/subscriptions/5.31-6.6/reflect/inspect/main.go b/subscriptions/5.31-6.6/reflect/inspect/main.go index 7f1eb6f7bf876fc8e9799eb23f756b3e45abb260..0f72ab9e64c84d5c04727dff310a706af5c44992 100644 --- a/subscriptions/5.31-6.6/reflect/inspect/main.go +++ b/subscriptions/5.31-6.6/reflect/inspect/main.go @@ -1,170 +1,170 @@ -package main - -import ( - "bytes" - "fmt" - "reflect" -) - -/* -获取函数入参出参、和结构体内函数时用reflect.TypeOf() -其他情况下,需要操作值时用reflect.ValueOf() -获取函数信息有关的用TypeOf, 调用值有关的用ValueOf - */ - -func main() { - u := User{ - Name: "robert lu", - Age: 24, - Married: false, - } - inspectStruct(u) - fmt.Println() - - // 透视不可导出字段 - inspectStruct(bytes.Buffer{}) - - // 透视map - m := map[int]string{ - 1: "lu", - 2: "ji", - } - inspectMap(m) - fmt.Println() - - // 透视slice - inspectSliceArray([]int{1, 3, 6}) - fmt.Println() - - // 透视func - inspectFunc("Add", Add) - inspectFunc("Greeting", Greeting) - - // 透视结构体中的定义的func - u1 := User{ - Name: "jsy", - Age: 24, - Married: false, - } - inspectMethod(&u1) -} - -// reflect.ValueOf():获取反射值对象; -// reflect.Value.NumField():从结构体的反射值对象中获取它的字段个数; -// reflect.Value.Field(i):从结构体的反射值对象中获取第i个字段的反射值对象; -// reflect.Kind():从反射值对象中获取种类; -// reflect.Int()/reflect.Uint()/reflect.String()/reflect.Bool():这些方法从反射值对象获取出具体类型。 -func inspectStruct(u interface{}) { - // 获取反射值对象 - v := reflect.ValueOf(u) - // NumField和Field函数只有对象是结构体时才能调用,否则会panic - for i := 0; i < v.NumField(); i++ { - field := v.Field(i) - // 这里是对field的底层类型进(反射类型)行判断 - switch field.Kind() { - case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64: - // field.Int()返回int64类型,field.Uint()返回Uint64类型(返回相应的最大范围的类型) - fmt.Printf("field: %d, type: %s, value: %d\n", i, field.Type().Name(), field.Int()) - case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64: - fmt.Printf("field: %d, type: %s, value: %d\n", i, field.Type().Name(), field.Uint()) - case reflect.Bool: - // %t表示布尔类型的值,%q表示单引号围绕的字符串字面值 - fmt.Printf("field: %d, type: %s, value: %t\n", i, field.Type().Name(), field.Bool()) - case reflect.String: - fmt.Printf("field: %d, type: %s, value: %q\n", i, field.Type().Name(), field.String()) - default: - fmt.Printf("field: %d unhandled kind:%s\n", i, field.Kind()) - } - } -} - -// reflect.Value.MapKeys():将每个键的reflect.Value对象组成一个切片返回; -// reflect.Value.MapIndex(k):传入键的reflect.Value对象,返回值的reflect.Value; -// 然后可以对键和值的reflect.Value进行和上面一样的处理。 -func inspectMap(m interface{}) { - v := reflect.ValueOf(m) - // 可以对k和field使用switch语句进行类型判断 - // MapKeys()和MapIndex(k)方法只能在原对象是map类型时才能调用,否则会panic - for _, k := range v.MapKeys() { - field := v.MapIndex(k) - // Interface()方法以空接口的形式返回内部包含的值 - fmt.Printf("%v => %v, type: %s, value: %v\n", k.Interface(), field.Interface(), k.Kind(), field.Kind()) - } -} - -// Len()和Index(i)方法只能在原对象是切片,数组或字符串时才能调用,其他类型会panic。 -func inspectSliceArray(sa interface{}) { - v := reflect.ValueOf(sa) - fmt.Printf("%c", '[') - for i := 0; i < v.Len(); i++ { - elem := v.Index(i) - fmt.Printf("%v ", elem.Interface()) - } - fmt.Printf("%c", ']') - fmt.Printf(", type: %v\n", v.Kind()) -} - -func Add(a, b int) int { - return a + b -} - -func Greeting(name string) string { - return "hello, " + name -} - -// 只有在原对象是函数类型的时候才能调用NumIn()/In()/NumOut()/Out()这些方法,其他类型会panic。 -// reflect.Type.NumIn():获取函数参数个数; -// reflect.Type.In(i):获取第i个参数的reflect.Type; -// reflect.Type.NumOut():获取函数返回值个数; -// reflect.Type.Out(i):获取第i个返回值的reflect.Type。 -func inspectFunc(name string, f interface{}) { - t := reflect.TypeOf(f) - fmt.Printf("%v input: ", name) - for i := 0; i < t.NumIn(); i++ { - ti := t.In(i) - fmt.Print(ti.Name()) - fmt.Print(" ") - } - fmt.Println() - - fmt.Printf("%v output: ", name) - for i := 0; i < t.NumOut(); i++ { - to := t.Out(i) - fmt.Print(to.Name()) - fmt.Print(" ") - } - fmt.Println("\n===========") -} - -type User struct { - Name string - Age int - Married bool -} - -// 设置名字 -func (u *User) SetName(name string) { - u.Name = name -} - -// 设置年龄 -func (u *User) SetAge(age int) { - u.Age = age -} - -// reflect.Value也定义了NumMethod()/Method(i)这些方法。区别在于:reflect.Type.Method(i)返回的是一个reflect.Method对象, -// 可以获取方法名、类型、是结构体中的第几个方法等信息。如果要通过这个reflect.Method调用方法,必须使用Func字段,而且要传入接收器的reflect.Value作为第一个参数 -// -// reflect.Value.Method(i)返回一个reflect.Value对象,它总是以调用Method(i)方法的reflect.Value作为接收器对象, -// 不需要额外传入。而且直接使用Call()发起方法调用 -func inspectMethod(o interface{}) { - t := reflect.TypeOf(o) - sl := []interface{}{1, "jsy"} - for i := 0; i < t.NumMethod(); i++ { - m := t.Method(i) - fmt.Println(m) - // 如果要通过这个reflect.Method调用方法,必须使用Func字段,而且要传入接收器的reflect.Value作为第一个参数 - fmt.Println(m.Func.Call([]reflect.Value{reflect.ValueOf(o), reflect.ValueOf(sl[i])})) - } - fmt.Println(o) -} +package main + +import ( + "bytes" + "fmt" + "reflect" +) + +/* +获取函数入参出参、和结构体内函数时用reflect.TypeOf() +其他情况下,需要操作值时用reflect.ValueOf() +获取函数信息有关的用TypeOf, 调用值有关的用ValueOf + */ + +func main() { + u := User{ + Name: "robert lu", + Age: 24, + Married: false, + } + inspectStruct(u) + fmt.Println() + + // 透视不可导出字段 + inspectStruct(bytes.Buffer{}) + + // 透视map + m := map[int]string{ + 1: "lu", + 2: "ji", + } + inspectMap(m) + fmt.Println() + + // 透视slice + inspectSliceArray([]int{1, 3, 6}) + fmt.Println() + + // 透视func + inspectFunc("Add", Add) + inspectFunc("Greeting", Greeting) + + // 透视结构体中的定义的func + u1 := User{ + Name: "jsy", + Age: 24, + Married: false, + } + inspectMethod(&u1) +} + +// reflect.ValueOf():获取反射值对象; +// reflect.Value.NumField():从结构体的反射值对象中获取它的字段个数; +// reflect.Value.Field(i):从结构体的反射值对象中获取第i个字段的反射值对象; +// reflect.Kind():从反射值对象中获取种类; +// reflect.Int()/reflect.Uint()/reflect.String()/reflect.Bool():这些方法从反射值对象获取出具体类型。 +func inspectStruct(u interface{}) { + // 获取反射值对象 + v := reflect.ValueOf(u) + // NumField和Field函数只有对象是结构体时才能调用,否则会panic + for i := 0; i < v.NumField(); i++ { + field := v.Field(i) + // 这里是对field的底层类型进(反射类型)行判断 + switch field.Kind() { + case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64: + // field.Int()返回int64类型,field.Uint()返回Uint64类型(返回相应的最大范围的类型) + fmt.Printf("field: %d, type: %s, value: %d\n", i, field.Type().Name(), field.Int()) + case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64: + fmt.Printf("field: %d, type: %s, value: %d\n", i, field.Type().Name(), field.Uint()) + case reflect.Bool: + // %t表示布尔类型的值,%q表示单引号围绕的字符串字面值 + fmt.Printf("field: %d, type: %s, value: %t\n", i, field.Type().Name(), field.Bool()) + case reflect.String: + fmt.Printf("field: %d, type: %s, value: %q\n", i, field.Type().Name(), field.String()) + default: + fmt.Printf("field: %d unhandled kind:%s\n", i, field.Kind()) + } + } +} + +// reflect.Value.MapKeys():将每个键的reflect.Value对象组成一个切片返回; +// reflect.Value.MapIndex(k):传入键的reflect.Value对象,返回值的reflect.Value; +// 然后可以对键和值的reflect.Value进行和上面一样的处理。 +func inspectMap(m interface{}) { + v := reflect.ValueOf(m) + // 可以对k和field使用switch语句进行类型判断 + // MapKeys()和MapIndex(k)方法只能在原对象是map类型时才能调用,否则会panic + for _, k := range v.MapKeys() { + field := v.MapIndex(k) + // Interface()方法以空接口的形式返回内部包含的值 + fmt.Printf("%v => %v, type: %s, value: %v\n", k.Interface(), field.Interface(), k.Kind(), field.Kind()) + } +} + +// Len()和Index(i)方法只能在原对象是切片,数组或字符串时才能调用,其他类型会panic。 +func inspectSliceArray(sa interface{}) { + v := reflect.ValueOf(sa) + fmt.Printf("%c", '[') + for i := 0; i < v.Len(); i++ { + elem := v.Index(i) + fmt.Printf("%v ", elem.Interface()) + } + fmt.Printf("%c", ']') + fmt.Printf(", type: %v\n", v.Kind()) +} + +func Add(a, b int) int { + return a + b +} + +func Greeting(name string) string { + return "hello, " + name +} + +// 只有在原对象是函数类型的时候才能调用NumIn()/In()/NumOut()/Out()这些方法,其他类型会panic。 +// reflect.Type.NumIn():获取函数参数个数; +// reflect.Type.In(i):获取第i个参数的reflect.Type; +// reflect.Type.NumOut():获取函数返回值个数; +// reflect.Type.Out(i):获取第i个返回值的reflect.Type。 +func inspectFunc(name string, f interface{}) { + t := reflect.TypeOf(f) + fmt.Printf("%v input: ", name) + for i := 0; i < t.NumIn(); i++ { + ti := t.In(i) + fmt.Print(ti.Name()) + fmt.Print(" ") + } + fmt.Println() + + fmt.Printf("%v output: ", name) + for i := 0; i < t.NumOut(); i++ { + to := t.Out(i) + fmt.Print(to.Name()) + fmt.Print(" ") + } + fmt.Println("\n===========") +} + +type User struct { + Name string + Age int + Married bool +} + +// 设置名字 +func (u *User) SetName(name string) { + u.Name = name +} + +// 设置年龄 +func (u *User) SetAge(age int) { + u.Age = age +} + +// reflect.Value也定义了NumMethod()/Method(i)这些方法。区别在于:reflect.Type.Method(i)返回的是一个reflect.Method对象, +// 可以获取方法名、类型、是结构体中的第几个方法等信息。如果要通过这个reflect.Method调用方法,必须使用Func字段,而且要传入接收器的reflect.Value作为第一个参数 +// +// reflect.Value.Method(i)返回一个reflect.Value对象,它总是以调用Method(i)方法的reflect.Value作为接收器对象, +// 不需要额外传入。而且直接使用Call()发起方法调用 +func inspectMethod(o interface{}) { + t := reflect.TypeOf(o) + sl := []interface{}{1, "jsy"} + for i := 0; i < t.NumMethod(); i++ { + m := t.Method(i) + fmt.Println(m) + // 如果要通过这个reflect.Method调用方法,必须使用Func字段,而且要传入接收器的reflect.Value作为第一个参数 + fmt.Println(m.Func.Call([]reflect.Value{reflect.ValueOf(o), reflect.ValueOf(sl[i])})) + } + fmt.Println(o) +} diff --git a/subscriptions/5.31-6.6/reflect/interface/main.go b/subscriptions/5.31-6.6/reflect/interface/main.go index 09ac9727b0ee2e7d0bdc91d49bb9b7f9e4a15c44..3a39f8d379312abaaab126e0a1418ae6698bfa9f 100644 --- a/subscriptions/5.31-6.6/reflect/interface/main.go +++ b/subscriptions/5.31-6.6/reflect/interface/main.go @@ -1,41 +1,41 @@ -package main - -import "fmt" - -// 定义一个名为Animal的接口,该接口定义了一个Speak方法 -type Animal interface { - Speak() -} - -type Cat struct { -} - -// Cat结构体实现了Animal接口中的Speak方法 -func (c Cat) Speak() { - fmt.Println("Meow") -} - -type Dog struct { -} - -// Dog类实现了Animal接口的Speak方法 -func (d Dog) Speak() { - fmt.Println("Bark") -} - -func main() { - // 1. 必须实现了Animal接口所有方法的变量,才能赋给Animal接口类型的变量 - // 接口变量包括两部分,类型和值,类型是赋值给接口变量的的值的类型,值是赋值给接口变量的值 - // 2. 赋给接口变量的结构体所实现的方法必须包含接口中定义的所有方法 - // 3. bytes.Buffer同时实现了io.Reader和io.Writer两个接口,所以bytes.Buffer对象可以赋值给io.Reader变量r, - // 同时r可以断言为io.Writer, 因为r中存储的值也实现了io.Writer接口 - // 4. 所有类型的值均可以赋给 没有约定任何方法的接口即空接口, - // 5.接口变量之间类型断言也好,直接赋值也好,其内部存储的(type, value)类型-值对是没有变化的。只是通过不同的接口能调用的方法有所不同而已。 - // 也是由于这个原因,接口变量中存储的值一定不是接口类型。 - var a Animal - a = Cat{} - a.Speak() - - a = Dog{} - a.Speak() -} +package main + +import "fmt" + +// 定义一个名为Animal的接口,该接口定义了一个Speak方法 +type Animal interface { + Speak() +} + +type Cat struct { +} + +// Cat结构体实现了Animal接口中的Speak方法 +func (c Cat) Speak() { + fmt.Println("Meow") +} + +type Dog struct { +} + +// Dog类实现了Animal接口的Speak方法 +func (d Dog) Speak() { + fmt.Println("Bark") +} + +func main() { + // 1. 必须实现了Animal接口所有方法的变量,才能赋给Animal接口类型的变量 + // 接口变量包括两部分,类型和值,类型是赋值给接口变量的的值的类型,值是赋值给接口变量的值 + // 2. 赋给接口变量的结构体所实现的方法必须包含接口中定义的所有方法 + // 3. bytes.Buffer同时实现了io.Reader和io.Writer两个接口,所以bytes.Buffer对象可以赋值给io.Reader变量r, + // 同时r可以断言为io.Writer, 因为r中存储的值也实现了io.Writer接口 + // 4. 所有类型的值均可以赋给 没有约定任何方法的接口即空接口, + // 5.接口变量之间类型断言也好,直接赋值也好,其内部存储的(type, value)类型-值对是没有变化的。只是通过不同的接口能调用的方法有所不同而已。 + // 也是由于这个原因,接口变量中存储的值一定不是接口类型。 + var a Animal + a = Cat{} + a.Speak() + + a = Dog{} + a.Speak() +} diff --git a/subscriptions/5.31-6.6/reflect/invoke/main.go b/subscriptions/5.31-6.6/reflect/invoke/main.go index 758890149d75b17711cde2055c82c8b03f6b87d6..4c8d9217edcfbe4c4e3116b49549c2b12320bfc3 100644 --- a/subscriptions/5.31-6.6/reflect/invoke/main.go +++ b/subscriptions/5.31-6.6/reflect/invoke/main.go @@ -1,93 +1,93 @@ -package main - -import ( - "fmt" - "reflect" -) - -func main() { - invoke(Add, 1, 2) - m := Math{ - a: 10, - b: 2, - } - invokeMethod(m, "Add") -} - -func Add(a, b int) int { - return a + b -} - -func Greeting(name string) string { - return "hello" + name -} - -// ValueOf返回的反射值对象调用函数时直接调用v.Call -// TypeOf返回的反射类型对象调用函数时需要调用 t.Func.Call -func invoke(f interface{}, args ...interface{}) { - v := reflect.ValueOf(f) - - argsV := make([]reflect.Value, 0, len(args)) - for _, arg := range args { - argsV = append(argsV, reflect.ValueOf(arg)) - } - retList := v.Call(argsV) - for _, ret := range retList { - fmt.Println(ret.Interface()) - } -} - -type M struct { - a, b int - op rune -} - -func (m M) Op() int { - switch m.op { - case '+': - return m.a + m.b - case '-': - return m.a - m.b - case '*': - return m.a * m.b - case '/': - return m.a / m.b - default: - panic("invalid op") - } -} - -type Math struct { - a, b int -} - -func (m Math) Add() int { - return m.a + m.b -} - -func (m Math) Sub() int { - return m.a - m.b -} - -func (m Math) Mul() int { - return m.a * m.b -} - -func (m Math) Div() int { - return m.a / m.b -} - -// 通过反射调用接收器的方法 -func invokeMethod(obj interface{}, name string, args ...interface{}) { - v := reflect.ValueOf(obj) - m := v.MethodByName(name) - argVge := make([]reflect.Value, 0, len(args)) - for _, arg := range args { - argV = append(argV, reflect.ValueOf(arg)) - } - retList := m.Call(argV) - fmt.Println("ret: ") - for _, ret := range retList { - fmt.Println(ret.Interface()) - } -} +package main + +import ( + "fmt" + "reflect" +) + +func main() { + invoke(Add, 1, 2) + m := Math{ + a: 10, + b: 2, + } + invokeMethod(m, "Add") +} + +func Add(a, b int) int { + return a + b +} + +func Greeting(name string) string { + return "hello" + name +} + +// ValueOf返回的反射值对象调用函数时直接调用v.Call +// TypeOf返回的反射类型对象调用函数时需要调用 t.Func.Call +func invoke(f interface{}, args ...interface{}) { + v := reflect.ValueOf(f) + + argsV := make([]reflect.Value, 0, len(args)) + for _, arg := range args { + argsV = append(argsV, reflect.ValueOf(arg)) + } + retList := v.Call(argsV) + for _, ret := range retList { + fmt.Println(ret.Interface()) + } +} + +type M struct { + a, b int + op rune +} + +func (m M) Op() int { + switch m.op { + case '+': + return m.a + m.b + case '-': + return m.a - m.b + case '*': + return m.a * m.b + case '/': + return m.a / m.b + default: + panic("invalid op") + } +} + +type Math struct { + a, b int +} + +func (m Math) Add() int { + return m.a + m.b +} + +func (m Math) Sub() int { + return m.a - m.b +} + +func (m Math) Mul() int { + return m.a * m.b +} + +func (m Math) Div() int { + return m.a / m.b +} + +// 通过反射调用接收器的方法 +func invokeMethod(obj interface{}, name string, args ...interface{}) { + v := reflect.ValueOf(obj) + m := v.MethodByName(name) + argVge := make([]reflect.Value, 0, len(args)) + for _, arg := range args { + argV = append(argV, reflect.ValueOf(arg)) + } + retList := m.Call(argV) + fmt.Println("ret: ") + for _, ret := range retList { + fmt.Println(ret.Interface()) + } +} diff --git a/subscriptions/5.31-6.6/reflect/kind/main.go b/subscriptions/5.31-6.6/reflect/kind/main.go index 713346c52734178dc935d265f9d68f46bebdbaf8..b0df509bf1b5699c7d405ccb7255e0e8fb9515dc 100644 --- a/subscriptions/5.31-6.6/reflect/kind/main.go +++ b/subscriptions/5.31-6.6/reflect/kind/main.go @@ -1,59 +1,59 @@ -package main - -import ( - "fmt" - "reflect" -) - -type MyInt int - -/* -const ( - Invalid Kind = iota - Bool - Int - Int8 - Int16 - Int32 - Int64 - Uint - Uint8 - Uint16 - Uint32 - Uint64 - Uintptr - Float32 - Float64 - Complex64 - Complex128 - Array - Chan - Func - Interface - Map - Ptr - Slice - String - Struct - UnsafePointer -) - */ - -func main() { - var i int - var j MyInt - - // 两个类型之间的转换需要进行强制类型转换 - i = int(j) - ti := reflect.TypeOf(i) - fmt.Println("type of i: ", ti.String()) - - tj := reflect.TypeOf(j) - fmt.Println("type of j: ", tj.String()) - - // 打印底层数据类型 - // 两个类型的底层数据类型是一样的 - // 从反射值对象中获取种类,总共26种,定义在reflect中 - fmt.Println("kind of i: ", ti.Kind()) - fmt.Println("kind of j: ", tj.Kind()) -} +package main + +import ( + "fmt" + "reflect" +) + +type MyInt int + +/* +const ( + Invalid Kind = iota + Bool + Int + Int8 + Int16 + Int32 + Int64 + Uint + Uint8 + Uint16 + Uint32 + Uint64 + Uintptr + Float32 + Float64 + Complex64 + Complex128 + Array + Chan + Func + Interface + Map + Ptr + Slice + String + Struct + UnsafePointer +) + */ + +func main() { + var i int + var j MyInt + + // 两个类型之间的转换需要进行强制类型转换 + i = int(j) + ti := reflect.TypeOf(i) + fmt.Println("type of i: ", ti.String()) + + tj := reflect.TypeOf(j) + fmt.Println("type of j: ", tj.String()) + + // 打印底层数据类型 + // 两个类型的底层数据类型是一样的 + // 从反射值对象中获取种类,总共26种,定义在reflect中 + fmt.Println("kind of i: ", ti.Kind()) + fmt.Println("kind of j: ", tj.Kind()) +} diff --git a/subscriptions/5.31-6.6/reflect/type-assert/main.go b/subscriptions/5.31-6.6/reflect/type-assert/main.go index f17c7221cb02fd1c71285a45bb89f4d7fcc4e823..f9c353f6cc393b063c1c5e51306e2a6615b50026 100644 --- a/subscriptions/5.31-6.6/reflect/type-assert/main.go +++ b/subscriptions/5.31-6.6/reflect/type-assert/main.go @@ -1,32 +1,32 @@ -package main - -import "fmt" - -// 声明一个animal接口 -type Animal interface { - Speak() -} - -type Cat struct { - Name string -} - -func (c Cat) Speak() { - fmt.Println("Meow") -} - -func main() { - var a Animal - a = Cat{Name: "coder"} - a.Speak() - - // 如果类型断言与变量的实际类型不符,则会panic - // 可以使用t, ok := a.(cat), 如果类型不符不会返回panic,ok的值会为false - // t := a.(Cat) - t, ok := a.(Cat) - if !ok { - fmt.Println("类型断言不符") - } else { - fmt.Println(t.Name) - } -} +package main + +import "fmt" + +// 声明一个animal接口 +type Animal interface { + Speak() +} + +type Cat struct { + Name string +} + +func (c Cat) Speak() { + fmt.Println("Meow") +} + +func main() { + var a Animal + a = Cat{Name: "coder"} + a.Speak() + + // 如果类型断言与变量的实际类型不符,则会panic + // 可以使用t, ok := a.(cat), 如果类型不符不会返回panic,ok的值会为false + // t := a.(Cat) + t, ok := a.(Cat) + if !ok { + fmt.Println("类型断言不符") + } else { + fmt.Println(t.Name) + } +}