Menu
CoddyTech

空接口(any)

本课属于 Coddy GO 学习旅程的“面向对象编程”单元。第 28 课,共 107 课。

空接口是没有任何方法的接口。由于 Go 中的每种类型至少有 0 个方法,因此每种类型都会自动满足空接口。这使空接口能够保存任何类型的值。

var anything interface{}

anything = 42
anything = "hello"
anything = true
anything = []int{1, 2, 3}

从 Go 1.18 开始,引入了关键字 any,作为 interface{} 的别名。它们完全可以互换,但 any 看起来更简洁。

var value any = "Go is awesome"

当你需要处理类型未知或各不相同的值时,空接口就很有用。像 fmt.Println 这样的函数会使用它来接受任意类型的参数:

func PrintAnything(v any) {
    fmt.Println("Value:", v)
}

func main() {
    PrintAnything(100)
    PrintAnything("text")
    PrintAnything(3.14)
}

不过,这也有代价。当一个值存储在空接口中时,你就无法再访问它的具体类型信息。

如果不先提取底层类型,就不能直接调用方法或访问字段。接下来的几课会介绍如何使用类型断言和类型开关,从空接口中获取具体类型。

challenge icon

挑战

简单

让我们使用空接口构建一个灵活的存储容器,它可以保存任意类型的值。你将创建一个简单的盒子,展示 any 如何让你在同一个结构体中存储不同类型的值。

你需要将代码分布在两个文件中:

  • box.go:定义一个 Box 结构体,其中只有一个类型为 any 的字段 Content。创建一个 NewBox 构造函数,它接受任意类型的值,并返回一个指向包含该值的 Box 的指针。添加一个 Describe 方法,返回一个字符串,说明盒子中存储的内容。
  • main.go:从输入中读取不同的值,创建分别包含整数、字符串和布尔值的盒子,然后打印每个盒子的描述,展示同一种 Box 类型如何保存完全不同的值。

输入将按以下格式提供:

  • 第 1 行:一个整数值
  • 第 2 行:一个字符串值
  • 第 3 行:一个布尔值(true 或 false)

你的 Describe 方法应返回符合以下格式的字符串:

Box contains: [value]

例如,给定 42、hello 和 true,你的输出应为:

Box contains: 42
Box contains: hello
Box contains: true

这里的关键在于,你的单个 Box 结构体可以存储整数、字符串或布尔值,这一切都归功于 any 类型可以接受任意类型的值。每个盒子保存的内容都不同,但它们的类型都是 Box。

亲手试试

package main

import (
	"bufio"
	"fmt"
	"os"
	"strconv"
	"strings"
)

func main() {
	reader := bufio.NewReader(os.Stdin)

	// 读取整数值
	line1, _ := reader.ReadString('\n')
	intVal, _ := strconv.Atoi(strings.TrimSpace(line1))

	// 读取字符串值
	line2, _ := reader.ReadString('\n')
	strVal := strings.TrimSpace(line2)

	// 读取布尔值
	line3, _ := reader.ReadString('\n')
	boolVal, _ := strconv.ParseBool(strings.TrimSpace(line3))

	// TODO: 使用 NewBox 为每个值创建盒子
	// TODO: 使用 Describe 方法打印每个盒子的描述

	// 使用这些变量以避免编译错误(实现时删除这些代码行)
	_ = intVal
	_ = strVal
	_ = boolVal

	// 输出格式示例:
	// fmt.Println(box.Describe())
}
quiz icon自我测试

这节课包含一个小测验。开始学习即可作答,并记录你的进度。

面向对象编程中的所有课

自己练习: Go 在线编译器