返回介绍

上卷 程序设计

中卷 标准库

下卷 运行时

源码剖析

附录

5.5.1 匿名

发布于 2024-10-12 19:15:48 字数 1973 浏览 0 评论 0 收藏 0

所谓匿名字段(anonymous field),是指没有名字,仅有类型的字段。也被称作嵌入字段、嵌入类型。

  • 隐式以类型名为字段名。
  • 嵌入类型与其指针类型隐式字段名相同。
  • 像直属字段那样直接访问嵌入类型成员。
type Attr struct {
	perm int
}

type File struct {
	Attr            // Attr: Attr
	name string
}

func main() {
	f := File {
		name: "test.dat",

		// 必须显式名称初始化。

		// perm: 0644,
		// ~~~~ unknown field 'perm' in struct literal of type File

		Attr: Attr{
			perm: 0644,
		},
	}

	// 像直属字段访问嵌入字段。
	fmt.Printf("%s, %o\n", f.name, f.perm)
}

嵌入其他包里的类型,隐式字段名字不含包名。

type data struct {
	os.File         // File: os.File
}

func main() {
	d := data{
		File: os.File{},
	}

	fmt.Printf("%#v\n", d)
}

接口指针多级指针 以外的任何 命名类型 都可作为匿名字段。

type data struct {
	*int              // int: *int(星号不是名字组成部分)
	
	// int
    // ~~~ int redeclared

    fmt.Stringer

	// *fmt.Stringer
	// ~~~~ embedded field type cannot be a pointer to an interface
}

func main() {

	_ = data{
		int: nil,
		Stringer: nil,
	}
}

重名

直属字段与嵌入类型成员存在重名问题。

编译器优先选择直属命名字段,或按嵌入层次逐级查找匿名类型成员。
如匿名类型成员被外层同名遮蔽,那么必须用显式字段名。

type File struct {
	name []byte
}

type Data struct {
	File
	name string    // 和 File.name 重名。
}

func main() {
	d := Data{
		name: "data",
		File: File{ []byte("file") },
	}
    
	d.name = "data2"               // 优先选择直属命名字段。
	d.File.name = []byte("file2")  // 显式字段名。
    
	fmt.Println(d.name, d.File.name)
}

如多个相同层次的匿名类型成员重名,就只能用显式字段名,因为编译器无法确定目标。

type File struct {
	name string
}

type Log struct {
	name string
}

type Data struct {
	File
	Log
}

func main() {
	d := Data{}
	
	// d.name = "name"
	// ~~~~~~ ambiguous selector d.name

	d.File.name = "file"
	d.Log.name = "log"
}

Go 并非传统意义上的 OOP 语言(封装、继承和多态),仅实现了最小机制。


匿名嵌入是 组合 (composition),而非 继承 (inheritance)。
结构虽然承载了 class 功能,但无法 多态 (polymorphisn),只能以方法集配合接口实现。

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。
列表为空,暂无数据
    我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
    原文