反射-类型
1.1 指针类型和值类型
- 普通情况下:Go语言在正常调用时,确实会自动处理方法的接收者类型,允许通过值类型的变量调用指针接收者的方法。
- 反射情况下:方法集的规则更为严格,且不会自动进行类型转换。因此,当你获取类型信息时,方法集的行为依赖于具体的类型(值类型或指针类型)。
- 反射和方法集总结
- 指针类型 *B:
- 包含*B的值接收者方法bv和指针接收者方法bp。
- 包含嵌入的A的值接收者方法av和指针接收者方法ap。
- 值类型 B:
- 包含B的值接收者方法bv。
- 包含嵌入的A的值接收者方法av。
- 指针类型 *B:
- 反射和方法集总结
package main
import (
"fmt"
)
type A int
type B struct {
A
}
func (A) av() { fmt.Println("A value method") }
func (*A) ap() { fmt.Println("A pointer method") }
func (B) bv() { fmt.Println("B value method") }
func (*B) bp() { fmt.Println("B pointer method") }
func normal() {
var b B
// 调用 B 的值接收者方法
b.bv() // 输出:B value method
// 调用 B 的指针接收者方法,编译器自动对 b 取地址
b.bp() // 输出:B pointer method
// 调用嵌入的 A 的值接收者方法
b.av() // 输出:A value method
// 调用嵌入的 A 的指针接收者方法,编译器自动对 b.A 取地址
b.ap() // 输出:A pointer method
}
func reflect() {
var b = B{5}
t := reflect.TypeOf(&b)
s := []reflect.Type{t, t.Elem()}
for _, t := range s {
fmt.Println(t, ":")
for i := 0; i < t.NumMethod(); i++ {
method := t.Method(i)
fmt.Printf(" %s - %s\n", method.Name, method.Type)
}
}
/*
*main.B :
av - func(*main.B).av()
ap - func(*main.B).ap()
bp - func(*main.B).bp()
bv - func(*main.B).bv()
main.B :值类型无法访问指针类型的方法
av - func(main.B).av()
bv - func(main.B).bv()
*/
}
1.2 类型转换和赋值
1. 类型转换
在 Go 语言中,类型转换是显式的,哪怕底层相同也需要使用强制转换的语法。Go 不会自动将一种类型转换为另一种类型,即使它们的底层类型是相同的
-
基本类型
convertedValue := TypeName(originalValue)
-
示例
package main import ( "fmt" ) type MyInt int func main() { var a int = 42 var b MyInt = MyInt(a) // 显式类型转换 fmt.Println(a, b) // 输出:42 42 }
MyInt
是一个新的命名类型,底层类型是 int
。虽然它们的底层类型相同,但需要显式地将 int
类型的变量转换为 MyInt
类型。
2.赋值
赋值是指将一个变量的值赋值给另一个变量。Go 对类型赋值有严格的规则,类型必须完全匹配,或者满足一定的条件(如接口实现)。
-
赋值规则
- 相同类型:如果类型相同,则可以直接赋值
- 接口赋值:如果一个变量实现了某个结构,那么可以把这个变量赋值给那个接口类型的变量
-
示例
package main import ( "fmt" ) type MyInt int type MyInterface interface { Method() } type MyStruct struct{} func (MyStruct) Method() {} func main() { var a int = 42 var b MyInt = MyInt(a) // 需要显式类型转换 // 相同类型之间的赋值 var c MyInt = b // 接口赋值 var s MyStruct var i MyInterface = s // MyStruct 实现了 MyInterface,可以赋值给接口类型变量 fmt.Println(a, b, c) i.Method() }
1.3 反射时类型判断
1.Implements
用于检测一个类型是否实现了一个接口
-
语法
func (t Type) Implements(u Type) bool
- 返回值:如果
t
实现了接口u
,则返回false
- 返回值:如果
-
示例
package main import ( "fmt" "reflect" ) type MyInterface interface { MyMethod() } type MyStruct struct{} func (m MyStruct) MyMethod() {} func main() { var myStruct MyStruct var myInterface MyInterface tStruct := reflect.TypeOf(myStruct) tInterface := reflect.TypeOf(&myInterface).Elem() fmt.Println(tStruct.Implements(tInterface)) // true }
MyStruct
实现了MyInterface
接口,Implements
函数检查这一实现关系并返回true
。
2.ConvertibleTo
ConvertibleTo
方法用于检查一个类型是否可以转换为另一种类型。
-
语法
func (t Type) ConvertibleTo(u Type) bool
- 返回值:true 如果类型 t 可以转换为类型 u,否则返回 false。
-
示例
package main import ( "fmt" "reflect" ) type MyInt int type MyFloat float64 func main() { tInt := reflect.TypeOf(0) tMyInt := reflect.TypeOf(MyInt(0)) tFloat := reflect.TypeOf(float64(0)) tMyFloat := reflect.TypeOf(MyFloat(0)) fmt.Println(tInt.ConvertibleTo(tFloat)) // true fmt.Println(tMyInt.ConvertibleTo(tFloat)) // true fmt.Println(tMyFloat.ConvertibleTo(tFloat)) // true fmt.Println(tInt.ConvertibleTo(tMyFloat)) // true fmt.Println(tFloat.ConvertibleTo(tInt)) // true fmt.Println(tFloat.ConvertibleTo(tMyInt)) // true fmt.Println(tMyFloat.ConvertibleTo(tMyInt)) // true }
3. AssignableTo
AssignableTo
方法用于检查一个类型的值是否可以赋值给另一种类型的变量
-
语法
func (t Type) AssignableTo(u Type) bool
- 返回值:true 如果类型 t 可以赋值给类型 u,否则返回 false。
-
示例
package main import ( "fmt" "reflect" ) type MyInt int func main() { tInt := reflect.TypeOf(0) tMyInt := reflect.TypeOf(MyInt(0)) fmt.Println(tInt.AssignableTo(tMyInt)) // false fmt.Println(tMyInt.AssignableTo(tInt)) // false var x int var y MyInt px := reflect.TypeOf(&x) py := reflect.TypeOf(&y) fmt.Println(px.AssignableTo(py)) // false fmt.Println(py.AssignableTo(px)) // false }