go类型 引用类型
切片(Slice)
映射(Map)
通道(Channel)
指针(Pointer)
接口(Interface)
这些类型的变量实际上存储的是对数据的引用,而不是数据本身。
非引用类型
基本类型 :整型(Integers)、浮点型(Floats)、布尔型(Booleans)
复合类型 :数组(Arrays)、结构体(Structs)
字符串(String)
空结构体 空结构体大小为0字节
节约内存,结合map,channel使用
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 package mainimport ( "fmt" "unsafe" )type struct1 struct { }func main () { a := struct1{} fmt.Println(unsafe.Sizeof(a)) fmt.Printf("%p\n" , &a) }
string 字符串拼接 直接使用”+“,会制造一个新的字符串
频繁操作string用strings.Builder,strings.Join
字符串指针 1 2 3 4 5 6 7 8 9 10 11 12 package mainimport ( "fmt" "unsafe" )func main () { fmt.Println(unsafe.Sizeof("abc" )) fmt.Println(unsafe.Sizeof("abcdefg" )) }
切片 切片共享底层,append函数,扩容的时候会换底层
map 必须先初始化,才可以使用
闭包 闭包捕获的是外部变量的引用
如果不想被捕获,有两种方式:传参,或者复制一份(对于引用类型,不适用 )
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 package mainimport "fmt" func main () { var num int = 10 modifyNum := func () { num:=num+5 fmt.Println(num) } modifyNum() fmt.Println(num) elements := make ([]int ,3 ,5 ) fmt.Printf("elements: %p\n" ,&elements) elements[0 ],elements[1 ],elements[2 ]=1 ,2 ,3 addElement := func (e int ) { fmt.Printf("elements: %p\n" ,&elements) elements[0 ]=e } addElement(4 ) fmt.Println(elements) addElement2 := func (ele []int ) { ele[0 ]=5 fmt.Printf("ele: %p\n" ,&ele) } addElement2(elements) fmt.Println(elements) }
defer 的执行顺序 defer执行顺序和调用顺序相反,类似于栈后进先出 (LIFO)。
defer在return之后 执行,但在函数退出之前,defer可以修改返回值。下面是一个例子:
panic
先执行defer,在执行panic!!!
panic不会叠加的方式存在,而是会被最近的panic覆盖,直到遇到recover为止。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 package mainimport "fmt" func panic1 () { defer func () { if err := recover (); err != nil { fmt.Println("Recovered in panic1:" , err) } }() defer func () { panic ("defer panic in panic1" ) }() panic ("panic in panic1" ) }func main () { panic1() fmt.Println("Main function continues after panic1." ) }
输出
1 2 Recovered in panic1: defer panic in panic1 Main function continues after panic1.
new和make
new(T) 返回的是一个指向类型 T 零值的指针 。它适用于所有类型,包括切片、映射、通道等,但返回的总是一个指向零值 的指针。对于切片,不会分配底层数组
make(T, args...) 只能用于切片、映射和通道的内存分配和初始化。它返回的是一个初始化后的 T 类型的实例,而不是指针。对于切片,make 还会分配底层数组 。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 package mainimport "fmt" func main () { a := new ([]int ) fmt.Println(*a == nil ) *a = append (*a, 1 ) fmt.Println(a, *a) b := make ([]int , 0 ) fmt.Println(b == nil ) b = append (b, 1 ) fmt.Println(&b, b) c := *new ([10 ]int ) fmt.Println(&c == nil ) fmt.Println(c) d := [10 ]int {} fmt.Println(&d == nil ) fmt.Println(d) }
双引号和反引号区别 双引号字符串支持转义
反引号不支持转义
反射 在 Go 语言中,反射的核心由 reflect 标准库提供,主要涉及两个类型:Type 和 Value。
reflect.Type 表示 Go 语言中的类型。它提供了类型的名称、种类(如 int、struct 等)以及可以进行哪些操作的信息。
reflect.Value 表示 Go 语言中的具体值。它可以用来获取或设置值、调用方法等。
主要方法 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 reflect.TypeOf() Elem() NumField() Field() FieldByIndex() NumMethod() Method() NumIn() In() NumOut() Out()
TypeOf
返回 i 的反射Type类型
注意Elem()将指针类型转化为普通类型
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 package mainimport ( "fmt" "reflect" )func getType () { typeInt := reflect.TypeOf(1 ) fmt.Println(typeInt) fmt.Println(typeInt.String()) fmt.Println(typeInt.Kind()) typeString := reflect.TypeOf("hello" ) fmt.Println(typeString) fmt.Println(typeString.String()) fmt.Println(typeString.Kind()) }type User struct { UserName string `我是Tag` Age int }func getType2 () { var u1 User typeUser1 := reflect.TypeOf(u1) fmt.Println(typeUser1) fmt.Println(typeUser1.String()) fmt.Println(typeUser1.Kind()) fmt.Println(typeUser1.Field(0 ).Name) var u2 = new (User) typeUser2 := reflect.TypeOf(u2) fmt.Println(typeUser2) fmt.Println(typeUser2.String()) fmt.Println(typeUser2.Kind()) var u3 = new (User) typeUser3 := reflect.TypeOf(u3).Elem() fmt.Println(typeUser3) fmt.Println(typeUser3.String()) fmt.Println(typeUser3.Kind()) }func main () { getType() getType2() }
获取成员变量详细信息
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 type User struct { UserName string `我是Tag` Age int student Student } type Student struct { score float32 } func getField () { typeUser := reflect.TypeOf(User{}) numField := typeUser.NumField() for i := 0 ; i < numField; i++ { field := typeUser.Field(i) fmt.Println("成员变量详情:" , field) } subField := typeUser.FieldByIndex([]int {2 , 0 }) fmt.Println(subField) }
获取成员方法详细信息
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 type User struct { UserName string `我是Tag` Age int } func (User) Insert() int { return 1 } func getMethod () { typeUser := reflect.TypeOf(User{}) numMethod := typeUser.NumMethod() for i := 0 ; i < numMethod; i++ { method := typeUser.Method(i) fmt.Println("成员方法详情:" , method) } }
获取方法入参出参详细信息
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 func Add (a, b int ) int { return a + b } func getFunc () { typeFunc := reflect.TypeOf(Add) fmt.Println("方法类型:" , typeFunc.Kind()) numIn := typeFunc.NumIn() fmt.Println("方法输入参数个数:" , numIn) numOut := typeFunc.NumOut() fmt.Println("方法输出参数个数:" , numOut) for i := 0 ; i < numIn; i++ { fmt.Printf("第 %d 个输入参数类型是 %s \n" , i, typeFunc.In(i)) } for i := 0 ; i < numOut; i++ { fmt.Printf("第 %d 个输出参数类型是 %s \n" , i, typeFunc.Out(i)) } }
ValueOf
reflect.ValueOf 的使用
1 2 3 4 5 6 7 8 func getValue () { intValue := reflect.ValueOf(1 ) stringValue := reflect.ValueOf("hello" ) userValue := reflect.ValueOf(User{}) fmt.Println(intValue) fmt.Println(stringValue) fmt.Println(userValue) }
Value 转 Type
1 2 3 4 5 6 func getValue () { intValue := reflect.ValueOf(1 ) intType := intValue.Type() fmt.Println(intType) }
指针结构体互相转换
1 2 3 4 5 6 7 8 9 10 func trans () { userValue := reflect.ValueOf(&User{}) fmt.Println(userValue.Kind()) userValuePtr := userValue.Elem() fmt.Println(userValuePtr.Kind()) userValue2 := userValuePtr.Addr() fmt.Println(userValue2.Kind()) }
反射类型转普通类型
1 2 3 4 5 6 7 8 9 10 11 12 13 func trans () { iValue := reflect.ValueOf(1 ) iValue.Int() iValue2 := iValue.Interface().(int ) fmt.Println(iValue2) userType := reflect.ValueOf(User{}) user := userType.Interface().(User) fmt.Println(user.UserName) }
通过反射修改基础类型的值
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 func changeValue () { var i = 10 iValue := reflect.ValueOf(&i) fmt.Println(iValue.Kind()) if iValue.CanAddr() { iValue.SetInt(20 ) fmt.Println("i = " , i) } iValue2 := iValue.Elem() fmt.Println(iValue2.Kind()) if iValue2.CanAddr() { iValue2.SetInt(30 ) fmt.Println("i = " , i) } }
通过反射修改结构体成员变量的值
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 type User struct { UserName string `我是Tag` Age int gender int } func changeValue () { var user = User{ UserName: "张三" , Age: 18 , } fmt.Println("修改前的值:" , user.UserName, user.Age) userValue := reflect.ValueOf(&user).Elem() if userValue.CanAddr() { userValue.FieldByName("UserName" ).SetString("李四" ) userValue.FieldByName("Age" ).SetInt(28 ) fmt.Println("修改后的值:" , user.UserName, user.Age) } }
通过反射修改嵌套结构体成员变量的值
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 type User struct { UserName string `我是Tag` Age int gender int Student Student } type Student struct { Score float32 } func changeValue () { var user = User{ UserName: "张三" , Student: Student{ Score: 98 , }, } userValue := reflect.ValueOf(&user).Elem() if userValue.CanAddr() { studentValue := userValue.FieldByName("Student" ) fmt.Println(studentValue.Kind()) studentValue.FieldByName("Score" ).SetFloat(59 ) fmt.Println(user.Student.Score) } }
通过反射修改 slice 切片中的值
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 type User struct { UserName string `我是Tag` Age int gender int } func changeValue () { var userSlice = make ([]*User, 3 , 5 ) userSlice[0 ] = &User{ UserName: "张三" , Age: 18 , } fmt.Println("修改前的数据:" , userSlice[0 ].UserName, userSlice[0 ].Age) sliceValue := reflect.ValueOf(userSlice) fmt.Println(sliceValue.CanAddr()) if sliceValue.Len() > 0 { sliceValue0 := sliceValue.Index(0 ) fmt.Println(sliceValue0.CanAddr()) fmt.Println(sliceValue0.Kind()) userValue := sliceValue0.Elem() userValue.FieldByName("UserName" ).SetString("李四" ) userValue.FieldByName("Age" ).SetInt(28 ) fmt.Println("修改后的数据:" , userSlice[0 ].UserName, userSlice[0 ].Age) } sliceValue.Index(1 ).Set(reflect.ValueOf(&User{ UserName: "王五" , Age: 16 , })) fmt.Println(userSlice[1 ].UserName, userSlice[1 ].Age) }
通过反射修改 map 中的值
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 func changeValue () { u1 := &User{ UserName: "张三" , Age: 18 , } u2 := &User{ UserName: "李四" , Age: 20 , } userMap := make (map [int ]*User, 5 ) userMap[0 ] = u1 userMap[1 ] = u2 mapValue := reflect.ValueOf(userMap) mapType := mapValue.Type() keyType := mapType.Key() fmt.Println("key的数据类型是:" , keyType) valueType := mapType.Elem() fmt.Println("value的数据类型是:" , valueType) u1Value := mapValue.MapIndex(reflect.ValueOf(1 )) fmt.Println("修改前的数据:" , userMap[1 ].UserName, userMap[1 ].Age) u1Value.Elem().FieldByName("Age" ).SetInt(28 ) fmt.Println("修改后的数据:" , userMap[1 ].UserName, userMap[1 ].Age) k3 := 2 u3 := &User{ UserName: "王五" , Age: 22 , } mapValue.SetMapIndex(reflect.ValueOf(k3), reflect.ValueOf(u3)) fmt.Println(userMap[k3].UserName, userMap[k3].Age) }
通过反射调用普通方法
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 func callFunc () { valueFunc := reflect.ValueOf(Add) fmt.Println(valueFunc.Kind()) typeFunc := valueFunc.Type() numIn := typeFunc.NumIn() params := make ([]reflect.Value, numIn) for i := 0 ; i < numIn; i++ { params[i] = reflect.ValueOf(1 ) } callResult := valueFunc.Call(params) for i := 0 ; i < len (callResult); i++ { fmt.Println(callResult[i]) } }
通过反射调用结构体的成员方法
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 type User struct { UserName string `我是Tag` Age int gender int Student Student } func (User) Insert(userName string ) int { return 1 } func callFunc () { user := &User{} userValue := reflect.ValueOf(user) insertMethod := userValue.MethodByName("Insert" ) callResult := insertMethod.Call([]reflect.Value{reflect.ValueOf("张三" )}) for i := 0 ; i < len (callResult); i++ { fmt.Println(callResult[i]) } }
案例 1. 动态方法调用 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 package mainimport ( "fmt" "reflect" )type Animal struct {}func (a *Animal) Speak(sound string ) string { return sound }func main () { a := Animal{} method := reflect.ValueOf(&a).MethodByName("Speak" ) args := []reflect.Value{reflect.ValueOf("Woof" )} result := method.Call(args) fmt.Println(result[0 ].String()) }
2. 访问和修改变量的值 1 2 3 4 5 6 7 8 9 10 11 12 13 14 package mainimport ( "fmt" "reflect" )func main () { x := 42 v := reflect.ValueOf(&x).Elem() fmt.Println("Before:" , v.Int()) v.SetInt(43 ) fmt.Println("After:" , v.Int()) }
3. 类型检查和断言 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 package mainimport ( "fmt" "reflect" )func typeCheck (values ...interface {}) { for _, value := range values { t := reflect.TypeOf(value) fmt.Printf("Value: %v, Type: %v\n" , value, t) } }func main () { typeCheck(42 , "hello" , true , 3.14 ) }
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 package mainimport ( "fmt" "reflect" )type User struct { Name string `json:"name"` Age int `json:"age"` }func main () { u := User{} t := reflect.TypeOf(u) for i := 0 ; i < t.NumField(); i++ { field := t.Field(i) fmt.Printf("%s: %s\n" , field.Name, field.Tag.Get("json" )) } }
5. 构建动态代理或中间件 此案例较为复杂,通常涉及到网络编程和较高级的反射技巧,难以在简短的代码中完全展示。不过,可以想象一个简化的场景,其中利用反射来动态调用指定的处理函数。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 package mainimport ( "fmt" "reflect" "time" )func Middleware (function interface {}, args ...interface {}) []reflect.Value { fn := reflect.ValueOf(function) if fn.Kind() != reflect.Func { panic ("Middleware expects a function" ) } in := make ([]reflect.Value, len (args)) for i, arg := range args { in[i] = reflect.ValueOf(arg) } fmt.Println("Before calling function:" , fn.Type().Name(), "at" , time.Now().Format(time.RFC3339)) result := fn.Call(in) fmt.Println("After calling function:" , fn.Type().Name(), "at" , time.Now().Format(time.RFC3339)) return result }func ExampleFunction (name string , age int ) { fmt.Printf("Executing ExampleFunction with args: name=%s, age=%d\n" , name, age) }func main () { Middleware(ExampleFunction, "John Doe" , 30 ) }
6. 实现通用函数和库 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 package mainimport ( "fmt" "reflect" )func printSlice (s interface {}) { val := reflect.ValueOf(s) if val.Kind() != reflect.Slice { fmt.Println("Not a slice" ) return } for i := 0 ; i < val.Len(); i++ { fmt.Println(val.Index(i)) } }func main () { printSlice([]int {1 , 2 , 3 }) printSlice([]string {"hello" , "world" }) }
7. 类型安全的动态编程 反射的使用使得可以检查类型信息,并据此执行类型安全的操作,例如,动态地处理不同类型的数据,但同时确保在编译时不会违反Go的类型系统。
8. 自定义序列化 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 package mainimport ( "fmt" "reflect" "strings" )func serializeStruct (s interface {}) string { val := reflect.ValueOf(s) t := val.Type() var parts []string for i := 0 ; i < val.NumField(); i++ { field := t.Field(i) value := val.Field(i) part := fmt.Sprintf("%s=%v" , field.Name, value) parts = append (parts, part) } return strings.Join(parts, ", " ) }type MyStruct struct { Name string Value int }func main () { s := MyStruct{Name: "Test" , Value: 42 } fmt.Println(serializeStruct(s)) }
runtime