Skip to content

Commit 0ed383a

Browse files
committed
20220426
1 parent 643eca3 commit 0ed383a

File tree

2 files changed

+132
-1
lines changed

2 files changed

+132
-1
lines changed

README.md

+1-1
Original file line numberDiff line numberDiff line change
@@ -79,7 +79,7 @@ ps:白天上班,晚上更新,尽量日更,比心
7979

8080
[第35章 反射编程](https://github.com/java-aodeng/golang-examples/blob/master/go-35/reflect_test.go)
8181

82-
第36章 万能程序
82+
[第36章 万能程序](https://github.com/java-aodeng/golang-examples/blob/master/go-36/flexible_reflect_test.go)
8383

8484
第37章 不安全编程
8585

go-36/flexible_reflect_test.go

+131
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,131 @@
1+
package go_36
2+
3+
import (
4+
"errors"
5+
"reflect"
6+
"testing"
7+
)
8+
9+
/*
10+
万能程序(原理都是利用go反射的特性,就和java差球不多,动态编程而已,理解了就是有手就行,看不懂这边建议直接放弃)
11+
12+
DeepEqual
13+
- 比较切片和map
14+
15+
万能赋值
16+
- 给两个不同的对象,但是相同属性的字段同时赋值
17+
18+
两个万能程序示例如下:
19+
*/
20+
21+
/*
22+
DeepEqual =====================万能程序1===========================
23+
- 比较切片和map
24+
*/
25+
func TestDeepEqual(t *testing.T) {
26+
a := map[int]string{1: "one", 2: "two", 3: "three"}
27+
b := map[int]string{1: "one", 2: "two", 3: "three"}
28+
//t.Log(a == b) //运行这行会报错,go语言不能直接比较 invalid operation: a == b (map can only be compared to nil)
29+
t.Log(reflect.DeepEqual(a, b))
30+
31+
s1 := []int{1, 2, 3}
32+
s2 := []int{1, 2, 3}
33+
s3 := []int{2, 3, 1}
34+
t.Log("s1 == s2?", reflect.DeepEqual(s1, s2))
35+
t.Log("s1 == s3?", reflect.DeepEqual(s1, s3))
36+
}
37+
38+
/* 运行结果:可以看到我们可以使用DeepEqual比较两个数组是否相等
39+
=== RUN TestDeepEqual
40+
flexible_reflect_test.go:21: true
41+
flexible_reflect_test.go:26: s1 == s2? true
42+
flexible_reflect_test.go:27: s1 == s3? false
43+
--- PASS: TestDeepEqual (0.00s)
44+
PASS
45+
*/
46+
47+
/*
48+
=====================万能程序2===========================
49+
万能赋值
50+
- 给两个不同的对象,但是相同属性的字段同时赋值。
51+
*/
52+
53+
//下面两个对象:相同属性为:Name,Age
54+
type Employee struct {
55+
EmployeeID string
56+
Name string `format:"normal"`
57+
Age int
58+
}
59+
60+
type Customer struct {
61+
CookieID string
62+
Name string
63+
Age int
64+
}
65+
66+
//给不同对象,相同属性赋值
67+
//st参数为传入的类型,settings为传入的值
68+
func fillBySettings(st interface{}, settings map[string]interface{}) error {
69+
70+
// func (v Value) Elem() Value
71+
// Elem returns the value that the interface v contains or that the pointer v points to.
72+
// It panics if v's Kind is not Interface or Ptr.
73+
// It returns the zero Value if v is nil.
74+
75+
if reflect.TypeOf(st).Kind() != reflect.Ptr { //判断参数是不是一个指针
76+
return errors.New("the first param should be a pointer to the struct type.")
77+
}
78+
// Elem() 获取指针指向的值
79+
if reflect.TypeOf(st).Elem().Kind() != reflect.Struct { //判断参数是不是一个结构体
80+
return errors.New("the first param should be a pointer to the struct type.")
81+
}
82+
83+
if settings == nil {
84+
return errors.New("settings is nil.")
85+
}
86+
87+
var (
88+
field reflect.StructField
89+
ok bool
90+
)
91+
92+
//这里其实就是循环遍历
93+
for k, v := range settings {
94+
if field, ok = (reflect.ValueOf(st)).Elem().Type().FieldByName(k); !ok {
95+
continue
96+
}
97+
//如果传入的对象的属性 和值的key相同就赋值
98+
if field.Type == reflect.TypeOf(v) {
99+
vstr := reflect.ValueOf(st)
100+
vstr = vstr.Elem()
101+
vstr.FieldByName(k).Set(reflect.ValueOf(v))
102+
}
103+
104+
}
105+
return nil
106+
}
107+
108+
func TestFillNameAndAge(t *testing.T) {
109+
//定义一个数组
110+
settings := map[string]interface{}{"Name": "Mike", "Age": 30}
111+
e := Employee{}
112+
if err := fillBySettings(&e, settings); err != nil {
113+
t.Fatal(err)
114+
}
115+
t.Log(e)
116+
c := new(Customer)
117+
if err := fillBySettings(c, settings); err != nil {
118+
t.Fatal(err)
119+
}
120+
t.Log(*c)
121+
}
122+
123+
/*
124+
运行结果:两个对象,相同的属性赋值相同了,这样有的场景下,能节省很多代码
125+
=== RUN TestFillNameAndAge
126+
flexible_reflect_test.go:114: { Mike 30}
127+
flexible_reflect_test.go:119: { Mike 30}
128+
--- PASS: TestFillNameAndAge (0.00s)
129+
PASS
130+
131+
*/

0 commit comments

Comments
 (0)