981 lines
24 KiB
Go
981 lines
24 KiB
Go
/*
|
||
02-empty-interface.go - Go 语言空接口详解
|
||
|
||
学习目标:
|
||
1. 理解空接口的概念和特性
|
||
2. 掌握空接口的使用场景
|
||
3. 学会空接口的类型断言
|
||
4. 了解空接口的性能考虑
|
||
5. 掌握空接口的实际应用
|
||
|
||
知识点:
|
||
- 空接口的定义 interface{}
|
||
- 空接口可以持有任何类型的值
|
||
- 空接口的类型断言和类型判断
|
||
- 空接口在泛型编程中的应用
|
||
- 空接口的性能影响
|
||
- 空接口的最佳实践
|
||
*/
|
||
|
||
package main
|
||
|
||
import (
|
||
"fmt"
|
||
"reflect"
|
||
"strconv"
|
||
)
|
||
|
||
func main() {
|
||
fmt.Println("=== Go 语言空接口详解 ===\n")
|
||
|
||
// 演示空接口的基本概念
|
||
demonstrateBasicEmptyInterface()
|
||
|
||
// 演示空接口的类型断言
|
||
demonstrateTypeAssertion()
|
||
|
||
// 演示空接口的类型判断
|
||
demonstrateTypeSwitch()
|
||
|
||
// 演示空接口的实际应用
|
||
demonstratePracticalUsage()
|
||
|
||
// 演示空接口的高级用法
|
||
demonstrateAdvancedUsage()
|
||
|
||
// 演示空接口的性能考虑
|
||
demonstratePerformanceConsiderations()
|
||
|
||
// 演示空接口的最佳实践
|
||
demonstrateBestPractices()
|
||
}
|
||
|
||
// demonstrateBasicEmptyInterface 演示空接口的基本概念
|
||
func demonstrateBasicEmptyInterface() {
|
||
fmt.Println("1. 空接口的基本概念:")
|
||
|
||
// 空接口的基本特性
|
||
fmt.Printf(" 空接口的基本特性:\n")
|
||
fmt.Printf(" - interface{} 不包含任何方法\n")
|
||
fmt.Printf(" - 可以持有任何类型的值\n")
|
||
fmt.Printf(" - 相当于其他语言中的 Object 或 Any\n")
|
||
fmt.Printf(" - 零值是 nil\n")
|
||
fmt.Printf(" - 运行时类型信息保存在接口中\n")
|
||
|
||
// 基本空接口示例
|
||
fmt.Printf(" 基本空接口示例:\n")
|
||
|
||
var empty interface{}
|
||
fmt.Printf(" 空接口零值: %v\n", empty)
|
||
fmt.Printf(" 空接口 == nil: %t\n", empty == nil)
|
||
|
||
// 存储不同类型的值
|
||
empty = 42
|
||
fmt.Printf(" 存储整数: %v (类型: %T)\n", empty, empty)
|
||
|
||
empty = "Hello, World!"
|
||
fmt.Printf(" 存储字符串: %v (类型: %T)\n", empty, empty)
|
||
|
||
empty = 3.14159
|
||
fmt.Printf(" 存储浮点数: %v (类型: %T)\n", empty, empty)
|
||
|
||
empty = true
|
||
fmt.Printf(" 存储布尔值: %v (类型: %T)\n", empty, empty)
|
||
|
||
empty = []int{1, 2, 3, 4, 5}
|
||
fmt.Printf(" 存储切片: %v (类型: %T)\n", empty, empty)
|
||
|
||
empty = map[string]int{"a": 1, "b": 2}
|
||
fmt.Printf(" 存储映射: %v (类型: %T)\n", empty, empty)
|
||
|
||
// 存储结构体
|
||
type Person struct {
|
||
Name string
|
||
Age int
|
||
}
|
||
|
||
empty = Person{Name: "Alice", Age: 30}
|
||
fmt.Printf(" 存储结构体: %v (类型: %T)\n", empty, empty)
|
||
|
||
// 存储指针
|
||
person := &Person{Name: "Bob", Age: 25}
|
||
empty = person
|
||
fmt.Printf(" 存储指针: %v (类型: %T)\n", empty, empty)
|
||
|
||
// 存储函数
|
||
empty = func(x int) int { return x * 2 }
|
||
fmt.Printf(" 存储函数: %v (类型: %T)\n", empty, empty)
|
||
|
||
fmt.Println()
|
||
}
|
||
|
||
// demonstrateTypeAssertion 演示空接口的类型断言
|
||
func demonstrateTypeAssertion() {
|
||
fmt.Println("2. 空接口的类型断言:")
|
||
|
||
fmt.Printf(" 类型断言用于从接口中提取具体类型的值\n")
|
||
|
||
// 基本类型断言
|
||
fmt.Printf(" 基本类型断言:\n")
|
||
|
||
var value interface{} = "Hello, Go!"
|
||
|
||
// 安全的类型断言
|
||
if str, ok := value.(string); ok {
|
||
fmt.Printf(" 类型断言成功: %s (长度: %d)\n", str, len(str))
|
||
} else {
|
||
fmt.Printf(" 类型断言失败\n")
|
||
}
|
||
|
||
// 不安全的类型断言(可能 panic)
|
||
str := value.(string)
|
||
fmt.Printf(" 直接类型断言: %s\n", str)
|
||
|
||
// 类型断言失败的情况
|
||
fmt.Printf(" 类型断言失败的情况:\n")
|
||
|
||
value = 42
|
||
if str, ok := value.(string); ok {
|
||
fmt.Printf(" 字符串断言成功: %s\n", str)
|
||
} else {
|
||
fmt.Printf(" 字符串断言失败,实际类型: %T\n", value)
|
||
}
|
||
|
||
// 断言为整数
|
||
if num, ok := value.(int); ok {
|
||
fmt.Printf(" 整数断言成功: %d\n", num)
|
||
}
|
||
|
||
// 多种类型断言
|
||
fmt.Printf(" 多种类型断言:\n")
|
||
|
||
values := []interface{}{
|
||
42,
|
||
"Hello",
|
||
3.14,
|
||
true,
|
||
[]int{1, 2, 3},
|
||
map[string]int{"key": 100},
|
||
}
|
||
|
||
for i, v := range values {
|
||
fmt.Printf(" 值 %d (%v):\n", i+1, v)
|
||
|
||
// 尝试不同的类型断言
|
||
if intVal, ok := v.(int); ok {
|
||
fmt.Printf(" 整数: %d\n", intVal)
|
||
} else if strVal, ok := v.(string); ok {
|
||
fmt.Printf(" 字符串: %s\n", strVal)
|
||
} else if floatVal, ok := v.(float64); ok {
|
||
fmt.Printf(" 浮点数: %.2f\n", floatVal)
|
||
} else if boolVal, ok := v.(bool); ok {
|
||
fmt.Printf(" 布尔值: %t\n", boolVal)
|
||
} else {
|
||
fmt.Printf(" 其他类型: %T\n", v)
|
||
}
|
||
}
|
||
|
||
fmt.Println()
|
||
}
|
||
|
||
// demonstrateTypeSwitch 演示空接口的类型判断
|
||
func demonstrateTypeSwitch() {
|
||
fmt.Println("3. 空接口的类型判断:")
|
||
|
||
fmt.Printf(" 类型 switch 是处理空接口的优雅方式\n")
|
||
|
||
// 基本类型 switch
|
||
fmt.Printf(" 基本类型 switch:\n")
|
||
|
||
values := []interface{}{
|
||
42,
|
||
"Hello, World!",
|
||
3.14159,
|
||
true,
|
||
[]int{1, 2, 3, 4, 5},
|
||
map[string]int{"a": 1, "b": 2},
|
||
nil,
|
||
struct{ Name string }{"Alice"},
|
||
}
|
||
|
||
for i, value := range values {
|
||
fmt.Printf(" 值 %d: ", i+1)
|
||
processValue(value)
|
||
}
|
||
|
||
// 复杂类型 switch
|
||
fmt.Printf(" 复杂类型 switch:\n")
|
||
|
||
complexValues := []interface{}{
|
||
Person{Name: "Alice", Age: 30},
|
||
&Person{Name: "Bob", Age: 25},
|
||
Employee{Person: Person{Name: "Charlie", Age: 35}, Position: "Developer"},
|
||
[]Person{{Name: "David", Age: 28}},
|
||
make(chan int),
|
||
func() { fmt.Println("函数") },
|
||
}
|
||
|
||
for i, value := range complexValues {
|
||
fmt.Printf(" 复杂值 %d: ", i+1)
|
||
processComplexValue(value)
|
||
}
|
||
|
||
// 类型 switch 的实际应用
|
||
fmt.Printf(" 类型 switch 的实际应用:\n")
|
||
|
||
// JSON 解析模拟
|
||
jsonData := map[string]interface{}{
|
||
"name": "Alice",
|
||
"age": 30,
|
||
"salary": 75000.50,
|
||
"active": true,
|
||
"skills": []interface{}{"Go", "Python", "JavaScript"},
|
||
"address": map[string]interface{}{
|
||
"city": "New York",
|
||
"zipcode": "10001",
|
||
},
|
||
}
|
||
|
||
fmt.Printf(" JSON 数据处理:\n")
|
||
processJSONData(jsonData, "")
|
||
|
||
fmt.Println()
|
||
}
|
||
|
||
// demonstratePracticalUsage 演示空接口的实际应用
|
||
func demonstratePracticalUsage() {
|
||
fmt.Println("4. 空接口的实际应用:")
|
||
|
||
// 应用1: 通用容器
|
||
fmt.Printf(" 应用1 - 通用容器:\n")
|
||
|
||
container := NewContainer()
|
||
|
||
// 存储不同类型的数据
|
||
container.Add("字符串数据")
|
||
container.Add(42)
|
||
container.Add(3.14)
|
||
container.Add([]int{1, 2, 3})
|
||
|
||
fmt.Printf(" 容器大小: %d\n", container.Size())
|
||
fmt.Printf(" 容器内容:\n")
|
||
for i := 0; i < container.Size(); i++ {
|
||
item := container.Get(i)
|
||
fmt.Printf(" [%d]: %v (%T)\n", i, item, item)
|
||
}
|
||
|
||
// 应用2: 配置系统
|
||
fmt.Printf(" 应用2 - 配置系统:\n")
|
||
|
||
config := NewConfig()
|
||
|
||
// 设置不同类型的配置
|
||
config.Set("app_name", "MyApp")
|
||
config.Set("port", 8080)
|
||
config.Set("debug", true)
|
||
config.Set("timeout", 30.5)
|
||
config.Set("features", []string{"auth", "logging", "metrics"})
|
||
|
||
// 获取配置
|
||
fmt.Printf(" 应用名称: %v\n", config.Get("app_name"))
|
||
fmt.Printf(" 端口: %v\n", config.Get("port"))
|
||
fmt.Printf(" 调试模式: %v\n", config.Get("debug"))
|
||
fmt.Printf(" 超时时间: %v\n", config.Get("timeout"))
|
||
fmt.Printf(" 功能列表: %v\n", config.Get("features"))
|
||
|
||
// 类型安全的获取
|
||
if port, ok := config.GetInt("port"); ok {
|
||
fmt.Printf(" 端口 (类型安全): %d\n", port)
|
||
}
|
||
|
||
if debug, ok := config.GetBool("debug"); ok {
|
||
fmt.Printf(" 调试模式 (类型安全): %t\n", debug)
|
||
}
|
||
|
||
// 应用3: 事件系统
|
||
fmt.Printf(" 应用3 - 事件系统:\n")
|
||
|
||
eventBus := NewEventBus()
|
||
|
||
// 注册事件处理器
|
||
eventBus.Subscribe("user_login", func(data interface{}) {
|
||
if user, ok := data.(map[string]interface{}); ok {
|
||
fmt.Printf(" 用户登录: %s\n", user["username"])
|
||
}
|
||
})
|
||
|
||
eventBus.Subscribe("order_created", func(data interface{}) {
|
||
if order, ok := data.(map[string]interface{}); ok {
|
||
fmt.Printf(" 订单创建: ID=%v, 金额=$%.2f\n",
|
||
order["id"], order["amount"])
|
||
}
|
||
})
|
||
|
||
// 发布事件
|
||
eventBus.Publish("user_login", map[string]interface{}{
|
||
"username": "alice",
|
||
"ip": "192.168.1.100",
|
||
})
|
||
|
||
eventBus.Publish("order_created", map[string]interface{}{
|
||
"id": 12345,
|
||
"amount": 99.99,
|
||
"items": []string{"laptop", "mouse"},
|
||
})
|
||
|
||
// 应用4: 数据转换
|
||
fmt.Printf(" 应用4 - 数据转换:\n")
|
||
|
||
converter := DataConverter{}
|
||
|
||
// 转换不同类型的数据
|
||
testData := []interface{}{
|
||
42,
|
||
"123",
|
||
3.14,
|
||
true,
|
||
"false",
|
||
[]int{1, 2, 3},
|
||
}
|
||
|
||
for _, data := range testData {
|
||
result := converter.ToString(data)
|
||
fmt.Printf(" %v (%T) -> \"%s\"\n", data, data, result)
|
||
}
|
||
|
||
fmt.Println()
|
||
}
|
||
|
||
// demonstrateAdvancedUsage 演示空接口的高级用法
|
||
func demonstrateAdvancedUsage() {
|
||
fmt.Println("5. 空接口的高级用法:")
|
||
|
||
// 高级用法1: 反射结合空接口
|
||
fmt.Printf(" 高级用法1 - 反射结合空接口:\n")
|
||
|
||
inspector := TypeInspector{}
|
||
|
||
values := []interface{}{
|
||
42,
|
||
"Hello",
|
||
[]int{1, 2, 3},
|
||
map[string]int{"a": 1},
|
||
Person{Name: "Alice", Age: 30},
|
||
&Person{Name: "Bob", Age: 25},
|
||
}
|
||
|
||
for _, value := range values {
|
||
inspector.Inspect(value)
|
||
}
|
||
|
||
// 高级用法2: 深拷贝
|
||
fmt.Printf(" 高级用法2 - 深拷贝:\n")
|
||
|
||
original := map[string]interface{}{
|
||
"name": "Alice",
|
||
"age": 30,
|
||
"address": map[string]interface{}{
|
||
"city": "New York",
|
||
"zip": "10001",
|
||
},
|
||
"hobbies": []interface{}{"reading", "swimming"},
|
||
}
|
||
|
||
copied := deepCopy(original)
|
||
|
||
fmt.Printf(" 原始数据: %v\n", original)
|
||
fmt.Printf(" 拷贝数据: %v\n", copied)
|
||
|
||
// 修改拷贝数据
|
||
if copiedMap, ok := copied.(map[string]interface{}); ok {
|
||
copiedMap["name"] = "Bob"
|
||
if address, ok := copiedMap["address"].(map[string]interface{}); ok {
|
||
address["city"] = "Boston"
|
||
}
|
||
}
|
||
|
||
fmt.Printf(" 修改后原始: %v\n", original)
|
||
fmt.Printf(" 修改后拷贝: %v\n", copied)
|
||
|
||
// 高级用法3: 序列化和反序列化
|
||
fmt.Printf(" 高级用法3 - 序列化和反序列化:\n")
|
||
|
||
serializer := SimpleSerializer{}
|
||
|
||
data := map[string]interface{}{
|
||
"user_id": 123,
|
||
"name": "Alice",
|
||
"active": true,
|
||
"score": 95.5,
|
||
}
|
||
|
||
// 序列化
|
||
serialized := serializer.Serialize(data)
|
||
fmt.Printf(" 序列化结果: %s\n", serialized)
|
||
|
||
// 反序列化
|
||
deserialized := serializer.Deserialize(serialized)
|
||
fmt.Printf(" 反序列化结果: %v\n", deserialized)
|
||
|
||
fmt.Println()
|
||
}
|
||
|
||
// demonstratePerformanceConsiderations 演示空接口的性能考虑
|
||
func demonstratePerformanceConsiderations() {
|
||
fmt.Println("6. 空接口的性能考虑:")
|
||
|
||
fmt.Printf(" 空接口的性能影响:\n")
|
||
fmt.Printf(" - 类型信息存储开销\n")
|
||
fmt.Printf(" - 装箱和拆箱成本\n")
|
||
fmt.Printf(" - 类型断言的运行时检查\n")
|
||
fmt.Printf(" - 垃圾回收压力增加\n")
|
||
|
||
// 性能对比示例
|
||
fmt.Printf(" 性能对比示例:\n")
|
||
|
||
// 直接类型操作
|
||
var directSum int
|
||
for i := 0; i < 1000; i++ {
|
||
directSum += i
|
||
}
|
||
fmt.Printf(" 直接类型操作结果: %d\n", directSum)
|
||
|
||
// 空接口操作
|
||
var interfaceSum int
|
||
var values []interface{}
|
||
for i := 0; i < 1000; i++ {
|
||
values = append(values, i)
|
||
}
|
||
|
||
for _, v := range values {
|
||
if num, ok := v.(int); ok {
|
||
interfaceSum += num
|
||
}
|
||
}
|
||
fmt.Printf(" 空接口操作结果: %d\n", interfaceSum)
|
||
|
||
// 内存使用对比
|
||
fmt.Printf(" 内存使用对比:\n")
|
||
|
||
// 直接存储
|
||
directSlice := make([]int, 1000)
|
||
for i := range directSlice {
|
||
directSlice[i] = i
|
||
}
|
||
|
||
// 接口存储
|
||
interfaceSlice := make([]interface{}, 1000)
|
||
for i := range interfaceSlice {
|
||
interfaceSlice[i] = i
|
||
}
|
||
|
||
fmt.Printf(" 直接存储切片长度: %d\n", len(directSlice))
|
||
fmt.Printf(" 接口存储切片长度: %d\n", len(interfaceSlice))
|
||
fmt.Printf(" 注意: 接口存储会有额外的内存开销\n")
|
||
|
||
fmt.Println()
|
||
}
|
||
|
||
// demonstrateBestPractices 演示空接口的最佳实践
|
||
func demonstrateBestPractices() {
|
||
fmt.Println("7. 空接口的最佳实践:")
|
||
|
||
fmt.Printf(" 最佳实践原则:\n")
|
||
fmt.Printf(" 1. 避免过度使用空接口\n")
|
||
fmt.Printf(" 2. 优先使用具体类型或定义的接口\n")
|
||
fmt.Printf(" 3. 使用类型断言时要检查成功与否\n")
|
||
fmt.Printf(" 4. 考虑使用泛型替代空接口(Go 1.18+)\n")
|
||
fmt.Printf(" 5. 在 API 边界谨慎使用空接口\n")
|
||
|
||
// 好的实践示例
|
||
fmt.Printf(" 好的实践示例:\n")
|
||
|
||
// 1. 明确的接口定义
|
||
fmt.Printf(" 1. 使用明确的接口而不是空接口:\n")
|
||
|
||
var printer Printer = ConsolePrinter{}
|
||
printer.Print("使用明确接口的消息")
|
||
|
||
// 2. 类型安全的容器
|
||
fmt.Printf(" 2. 类型安全的容器:\n")
|
||
|
||
stringContainer := NewTypedContainer[string]()
|
||
stringContainer.Add("Hello")
|
||
stringContainer.Add("World")
|
||
|
||
fmt.Printf(" 字符串容器: %v\n", stringContainer.GetAll())
|
||
|
||
intContainer := NewTypedContainer[int]()
|
||
intContainer.Add(1)
|
||
intContainer.Add(2)
|
||
intContainer.Add(3)
|
||
|
||
fmt.Printf(" 整数容器: %v\n", intContainer.GetAll())
|
||
|
||
// 3. 错误处理
|
||
fmt.Printf(" 3. 正确的错误处理:\n")
|
||
|
||
result, err := safeTypeAssertion("Hello, World!", "string")
|
||
if err != nil {
|
||
fmt.Printf(" 类型断言错误: %v\n", err)
|
||
} else {
|
||
fmt.Printf(" 类型断言成功: %v\n", result)
|
||
}
|
||
|
||
result, err = safeTypeAssertion(42, "string")
|
||
if err != nil {
|
||
fmt.Printf(" 类型断言错误: %v\n", err)
|
||
} else {
|
||
fmt.Printf(" 类型断言成功: %v\n", result)
|
||
}
|
||
|
||
// 避免的反模式
|
||
fmt.Printf(" 避免的反模式:\n")
|
||
fmt.Printf(" - 函数参数和返回值过度使用 interface{}\n")
|
||
fmt.Printf(" - 不检查类型断言的成功与否\n")
|
||
fmt.Printf(" - 在性能敏感的代码中大量使用空接口\n")
|
||
fmt.Printf(" - 用空接口替代适当的类型设计\n")
|
||
|
||
fmt.Println()
|
||
}
|
||
|
||
// ========== 类型定义 ==========
|
||
|
||
// 基本结构体
|
||
type Person struct {
|
||
Name string
|
||
Age int
|
||
}
|
||
|
||
type Employee struct {
|
||
Person
|
||
Position string
|
||
}
|
||
|
||
// 打印器接口
|
||
type Printer interface {
|
||
Print(message string)
|
||
}
|
||
|
||
type ConsolePrinter struct{}
|
||
|
||
func (cp ConsolePrinter) Print(message string) {
|
||
fmt.Printf(" [控制台] %s\n", message)
|
||
}
|
||
|
||
// ========== 实用工具类型 ==========
|
||
|
||
// 通用容器
|
||
type Container struct {
|
||
items []interface{}
|
||
}
|
||
|
||
func NewContainer() *Container {
|
||
return &Container{items: make([]interface{}, 0)}
|
||
}
|
||
|
||
func (c *Container) Add(item interface{}) {
|
||
c.items = append(c.items, item)
|
||
}
|
||
|
||
func (c *Container) Get(index int) interface{} {
|
||
if index >= 0 && index < len(c.items) {
|
||
return c.items[index]
|
||
}
|
||
return nil
|
||
}
|
||
|
||
func (c *Container) Size() int {
|
||
return len(c.items)
|
||
}
|
||
|
||
// 配置系统
|
||
type Config struct {
|
||
data map[string]interface{}
|
||
}
|
||
|
||
func NewConfig() *Config {
|
||
return &Config{data: make(map[string]interface{})}
|
||
}
|
||
|
||
func (c *Config) Set(key string, value interface{}) {
|
||
c.data[key] = value
|
||
}
|
||
|
||
func (c *Config) Get(key string) interface{} {
|
||
return c.data[key]
|
||
}
|
||
|
||
func (c *Config) GetString(key string) (string, bool) {
|
||
if value, exists := c.data[key]; exists {
|
||
if str, ok := value.(string); ok {
|
||
return str, true
|
||
}
|
||
}
|
||
return "", false
|
||
}
|
||
|
||
func (c *Config) GetInt(key string) (int, bool) {
|
||
if value, exists := c.data[key]; exists {
|
||
if num, ok := value.(int); ok {
|
||
return num, true
|
||
}
|
||
}
|
||
return 0, false
|
||
}
|
||
|
||
func (c *Config) GetBool(key string) (bool, bool) {
|
||
if value, exists := c.data[key]; exists {
|
||
if b, ok := value.(bool); ok {
|
||
return b, true
|
||
}
|
||
}
|
||
return false, false
|
||
}
|
||
|
||
// 事件系统
|
||
type EventBus struct {
|
||
handlers map[string][]func(interface{})
|
||
}
|
||
|
||
func NewEventBus() *EventBus {
|
||
return &EventBus{handlers: make(map[string][]func(interface{}))}
|
||
}
|
||
|
||
func (eb *EventBus) Subscribe(event string, handler func(interface{})) {
|
||
eb.handlers[event] = append(eb.handlers[event], handler)
|
||
}
|
||
|
||
func (eb *EventBus) Publish(event string, data interface{}) {
|
||
if handlers, exists := eb.handlers[event]; exists {
|
||
for _, handler := range handlers {
|
||
handler(data)
|
||
}
|
||
}
|
||
}
|
||
|
||
// 数据转换器
|
||
type DataConverter struct{}
|
||
|
||
func (dc DataConverter) ToString(value interface{}) string {
|
||
switch v := value.(type) {
|
||
case string:
|
||
return v
|
||
case int:
|
||
return strconv.Itoa(v)
|
||
case float64:
|
||
return strconv.FormatFloat(v, 'f', -1, 64)
|
||
case bool:
|
||
return strconv.FormatBool(v)
|
||
case []int:
|
||
result := "["
|
||
for i, num := range v {
|
||
if i > 0 {
|
||
result += ", "
|
||
}
|
||
result += strconv.Itoa(num)
|
||
}
|
||
result += "]"
|
||
return result
|
||
default:
|
||
return fmt.Sprintf("%v", v)
|
||
}
|
||
}
|
||
|
||
// 类型检查器
|
||
type TypeInspector struct{}
|
||
|
||
func (ti TypeInspector) Inspect(value interface{}) {
|
||
if value == nil {
|
||
fmt.Printf(" nil 值\n")
|
||
return
|
||
}
|
||
|
||
t := reflect.TypeOf(value)
|
||
v := reflect.ValueOf(value)
|
||
|
||
fmt.Printf(" 类型: %s, 种类: %s, 值: %v\n", t.String(), t.Kind().String(), value)
|
||
|
||
switch t.Kind() {
|
||
case reflect.Struct:
|
||
fmt.Printf(" 结构体字段数: %d\n", t.NumField())
|
||
for i := 0; i < t.NumField(); i++ {
|
||
field := t.Field(i)
|
||
fieldValue := v.Field(i)
|
||
fmt.Printf(" %s: %v (%s)\n", field.Name, fieldValue.Interface(), field.Type)
|
||
}
|
||
case reflect.Ptr:
|
||
fmt.Printf(" 指针指向: %s\n", t.Elem().String())
|
||
if !v.IsNil() {
|
||
fmt.Printf(" 指针值: %v\n", v.Elem().Interface())
|
||
}
|
||
case reflect.Slice:
|
||
fmt.Printf(" 切片长度: %d, 容量: %d\n", v.Len(), v.Cap())
|
||
fmt.Printf(" 元素类型: %s\n", t.Elem().String())
|
||
case reflect.Map:
|
||
fmt.Printf(" 映射长度: %d\n", v.Len())
|
||
fmt.Printf(" 键类型: %s, 值类型: %s\n", t.Key().String(), t.Elem().String())
|
||
}
|
||
}
|
||
|
||
// 简单序列化器
|
||
type SimpleSerializer struct{}
|
||
|
||
func (ss SimpleSerializer) Serialize(data interface{}) string {
|
||
switch v := data.(type) {
|
||
case map[string]interface{}:
|
||
result := "{"
|
||
first := true
|
||
for key, value := range v {
|
||
if !first {
|
||
result += ", "
|
||
}
|
||
result += fmt.Sprintf("\"%s\": %s", key, ss.serializeValue(value))
|
||
first = false
|
||
}
|
||
result += "}"
|
||
return result
|
||
default:
|
||
return ss.serializeValue(data)
|
||
}
|
||
}
|
||
|
||
func (ss SimpleSerializer) serializeValue(value interface{}) string {
|
||
switch v := value.(type) {
|
||
case string:
|
||
return fmt.Sprintf("\"%s\"", v)
|
||
case int:
|
||
return strconv.Itoa(v)
|
||
case float64:
|
||
return strconv.FormatFloat(v, 'f', -1, 64)
|
||
case bool:
|
||
return strconv.FormatBool(v)
|
||
default:
|
||
return fmt.Sprintf("\"%v\"", v)
|
||
}
|
||
}
|
||
|
||
func (ss SimpleSerializer) Deserialize(data string) interface{} {
|
||
// 简化的反序列化,实际应用中应该使用 JSON 包
|
||
if data == "true" {
|
||
return true
|
||
}
|
||
if data == "false" {
|
||
return false
|
||
}
|
||
if num, err := strconv.Atoi(data); err == nil {
|
||
return num
|
||
}
|
||
if num, err := strconv.ParseFloat(data, 64); err == nil {
|
||
return num
|
||
}
|
||
return data
|
||
}
|
||
|
||
// 类型安全的泛型容器(Go 1.18+)
|
||
type TypedContainer[T any] struct {
|
||
items []T
|
||
}
|
||
|
||
func NewTypedContainer[T any]() *TypedContainer[T] {
|
||
return &TypedContainer[T]{items: make([]T, 0)}
|
||
}
|
||
|
||
func (tc *TypedContainer[T]) Add(item T) {
|
||
tc.items = append(tc.items, item)
|
||
}
|
||
|
||
func (tc *TypedContainer[T]) Get(index int) T {
|
||
var zero T
|
||
if index >= 0 && index < len(tc.items) {
|
||
return tc.items[index]
|
||
}
|
||
return zero
|
||
}
|
||
|
||
func (tc *TypedContainer[T]) GetAll() []T {
|
||
return tc.items
|
||
}
|
||
|
||
// ========== 辅助函数 ==========
|
||
|
||
// 处理值的类型 switch
|
||
func processValue(value interface{}) {
|
||
switch v := value.(type) {
|
||
case nil:
|
||
fmt.Printf("nil 值\n")
|
||
case int:
|
||
fmt.Printf("整数: %d\n", v)
|
||
case string:
|
||
fmt.Printf("字符串: \"%s\" (长度: %d)\n", v, len(v))
|
||
case float64:
|
||
fmt.Printf("浮点数: %.3f\n", v)
|
||
case bool:
|
||
fmt.Printf("布尔值: %t\n", v)
|
||
case []int:
|
||
fmt.Printf("整数切片: %v (长度: %d)\n", v, len(v))
|
||
case map[string]int:
|
||
fmt.Printf("字符串到整数的映射: %v (大小: %d)\n", v, len(v))
|
||
default:
|
||
fmt.Printf("未知类型: %T, 值: %v\n", v, v)
|
||
}
|
||
}
|
||
|
||
// 处理复杂值的类型 switch
|
||
func processComplexValue(value interface{}) {
|
||
switch v := value.(type) {
|
||
case Person:
|
||
fmt.Printf("Person 结构体: %s (%d岁)\n", v.Name, v.Age)
|
||
case *Person:
|
||
fmt.Printf("Person 指针: %s (%d岁)\n", v.Name, v.Age)
|
||
case Employee:
|
||
fmt.Printf("Employee 结构体: %s - %s\n", v.Name, v.Position)
|
||
case []Person:
|
||
fmt.Printf("Person 切片: %d 个人\n", len(v))
|
||
case chan int:
|
||
fmt.Printf("整数通道\n")
|
||
case func():
|
||
fmt.Printf("无参数函数\n")
|
||
default:
|
||
fmt.Printf("其他复杂类型: %T\n", v)
|
||
}
|
||
}
|
||
|
||
// 处理 JSON 数据
|
||
func processJSONData(data map[string]interface{}, indent string) {
|
||
for key, value := range data {
|
||
fmt.Printf("%s %s: ", indent, key)
|
||
|
||
switch v := value.(type) {
|
||
case string:
|
||
fmt.Printf("\"%s\" (字符串)\n", v)
|
||
case float64:
|
||
fmt.Printf("%.2f (数字)\n", v)
|
||
case bool:
|
||
fmt.Printf("%t (布尔值)\n", v)
|
||
case []interface{}:
|
||
fmt.Printf("数组 [%d 个元素]\n", len(v))
|
||
for i, item := range v {
|
||
fmt.Printf("%s [%d]: %v (%T)\n", indent, i, item, item)
|
||
}
|
||
case map[string]interface{}:
|
||
fmt.Printf("对象 {%d 个字段}\n", len(v))
|
||
processJSONData(v, indent+" ")
|
||
default:
|
||
fmt.Printf("%v (%T)\n", v, v)
|
||
}
|
||
}
|
||
}
|
||
|
||
// 深拷贝函数
|
||
func deepCopy(original interface{}) interface{} {
|
||
switch v := original.(type) {
|
||
case map[string]interface{}:
|
||
copied := make(map[string]interface{})
|
||
for key, value := range v {
|
||
copied[key] = deepCopy(value)
|
||
}
|
||
return copied
|
||
case []interface{}:
|
||
copied := make([]interface{}, len(v))
|
||
for i, value := range v {
|
||
copied[i] = deepCopy(value)
|
||
}
|
||
return copied
|
||
default:
|
||
// 基本类型直接返回(值拷贝)
|
||
return v
|
||
}
|
||
}
|
||
|
||
// 安全的类型断言
|
||
func safeTypeAssertion(value interface{}, expectedType string) (interface{}, error) {
|
||
switch expectedType {
|
||
case "string":
|
||
if str, ok := value.(string); ok {
|
||
return str, nil
|
||
}
|
||
return nil, fmt.Errorf("期望 string 类型,实际是 %T", value)
|
||
case "int":
|
||
if num, ok := value.(int); ok {
|
||
return num, nil
|
||
}
|
||
return nil, fmt.Errorf("期望 int 类型,实际是 %T", value)
|
||
case "bool":
|
||
if b, ok := value.(bool); ok {
|
||
return b, nil
|
||
}
|
||
return nil, fmt.Errorf("期望 bool 类型,实际是 %T", value)
|
||
default:
|
||
return nil, fmt.Errorf("不支持的类型: %s", expectedType)
|
||
}
|
||
}
|
||
|
||
/*
|
||
运行这个程序:
|
||
go run 02-empty-interface.go
|
||
|
||
学习要点:
|
||
1. 空接口 interface{} 可以持有任何类型的值
|
||
2. 空接口是 Go 语言中最通用的类型
|
||
3. 使用类型断言从空接口中提取具体类型的值
|
||
4. 类型 switch 是处理空接口的优雅方式
|
||
5. 空接口在泛型编程和动态类型处理中很有用
|
||
|
||
空接口的特性:
|
||
1. 通用性:可以存储任何类型的值
|
||
2. 类型安全:通过类型断言保证类型安全
|
||
3. 运行时类型信息:保存值的动态类型信息
|
||
4. 零值:空接口的零值是 nil
|
||
5. 性能开销:有装箱拆箱的成本
|
||
|
||
类型断言:
|
||
1. 安全断言:value.(Type) 返回值和布尔标志
|
||
2. 不安全断言:value.(Type) 只返回值,失败时 panic
|
||
3. 类型 switch:switch value.(type) 处理多种类型
|
||
4. 类型检查:使用 ok 模式检查断言是否成功
|
||
|
||
常见应用场景:
|
||
1. 通用容器和集合
|
||
2. 配置系统和参数传递
|
||
3. JSON 和其他格式的数据处理
|
||
4. 事件系统和消息传递
|
||
5. 插件系统和动态加载
|
||
6. 序列化和反序列化
|
||
7. 反射和元编程
|
||
|
||
性能考虑:
|
||
1. 装箱开销:基本类型存储到接口需要装箱
|
||
2. 类型断言成本:运行时类型检查有开销
|
||
3. 内存使用:接口存储需要额外的类型信息
|
||
4. 垃圾回收:可能增加 GC 压力
|
||
|
||
最佳实践:
|
||
1. 避免过度使用空接口
|
||
2. 优先使用具体类型或定义的接口
|
||
3. 使用类型断言时检查成功与否
|
||
4. 考虑使用泛型替代空接口(Go 1.18+)
|
||
5. 在 API 设计中谨慎使用空接口
|
||
6. 提供类型安全的包装函数
|
||
|
||
何时使用空接口:
|
||
1. 需要存储不同类型的值
|
||
2. 处理动态类型的数据(如 JSON)
|
||
3. 实现通用的算法或容器
|
||
4. 与反射结合使用
|
||
5. 临时的类型转换需求
|
||
|
||
何时避免空接口:
|
||
1. 类型在编译时已知
|
||
2. 性能敏感的代码
|
||
3. 可以用泛型替代的场景
|
||
4. API 的公共接口设计
|
||
5. 简单的数据传递
|
||
|
||
注意事项:
|
||
1. nil 接口不能调用方法
|
||
2. 类型断言失败可能导致 panic
|
||
3. 空接口比较需要注意动态类型
|
||
4. 过度使用会降低代码的类型安全性
|
||
5. 调试时类型信息可能不够清晰
|
||
*/ |