一、什么是嵌入类型

先看如下代码:

type user struct {
name string
email string
} type admin struct {
user // Embedded Type
level string
}

可以看到admin结构中的一个成员是user,那么admin中就嵌入了user类型。

admin也叫做外部类型

user也叫做内部类型

二、外部类型和内部类型之间的关系和机制

func (u *user) notify() {
fmt.Printf("Sending user email to %s<%s>\n",
u.name,
u.email)
}

如上代码,实现了一个方法notify(),接收者是 *user。

func main() {
// Create an admin user.
ad := admin{
user: user{
name: "john smith",
email: "john@yahoo.com",
},
level: "super",
}
// We can access the inner type's method directly.
ad.user.notify()
// The inner type's method is promoted.
ad.notify()
}

main函数中定义了一个变量ad,并且进行了赋值

运行:

Sending user email to john smith<john@yahoo.com>
Sending user email to john smith<john@yahoo.com>

①没有编译错误

②notify()可以被ad.user调用是可以理解的,但是ad.notify()也能执行是为什么。

这里涉及到了一个嵌入类型背后的机制,内部类型提升 (感觉有点像C#、Java里面的继承,user是父类,admin是子类,admin的实例对象直接调用了父类的notify方法。)

进一步研究:我们再定义一个接口、以及一个接受该接口的函数。

接口,只有一个方法notify

type notifier interface {
notify()
}

函数,接受一个实现notifier接口的类型实例,内部就是调用notify方法

func sendNotification(n notifier) {
n.notify()
}

main方法如下

func main() {
// Create an admin user.
ad := admin{
user: user{
name: "john smith",
email: "john@yahoo.com",
},
level: "super",
} var user = ad.user
sendNotification(&user) sendNotification(&ad)
}

运行结果:

Sending user email to john smith<john@yahoo.com>
Sending user email to john smith<john@yahoo.com>

①可以看到这里传入 &user和&ad都是可以的,说明类型提升导致admin也是实现了notifier接口了。

②为什么穿&user和&ad,而不是直接传user和ad,这就涉及到了之前总结过的【方法集】的概念了。复习一下:

从上面两个表,可以知道由于方法的接收者是 *user ,所以说只有*user实现了该接口的方法,这就是为什么输入&user、&ad了

再进一步研究:我们在C#当中,如果使用了virtual作为修饰符在父类中写了一个方法,那么在子类中通过override可以重写这个方法,最终的结果就是调用的非父类的该方法,而是子类的,Go语言同样可以。

例如

// 通过admin 类型值的指针
// 调用的方法
func (a *admin) notify() {
fmt.Printf("Sending admin email to %s<%s>\n",
a.name,
a.email)
}

在刚刚的代码中,追加一个*admin作为接受者的方法。

运行结果如下:

Sending user email to john smith<john@yahoo.com>
Sending admin email to john smith<john@yahoo.com>

可以发现此时这两此运行的结果就不一样了,第二次sendNotification(&ad)调用的notify方法就是admin这个类型的了。

这表明,如果外部类型实现了notify 方法,内部类型的实现就不会被提升。不过内部类型的值一直存在,因此还可以通过直接访问内部类型的值,来调用没有被提升的内部类型实现的方法。

三、总结

综上:嵌入类型为Go语言类型提供了一种很好的扩展能力,通过内部类型的提升,使得外部类型拥有了内部类型的方法,也可以通过外部类型实现同样的方法来替代内部类型的。总体来说很像C#语言中的继承。

Go语言嵌入类型的更多相关文章

  1. Go 语言中的方法,接口和嵌入类型

    https://studygolang.com/articles/1113 概述 在 Go 语言中,如果一个结构体和一个嵌入字段同时实现了相同的接口会发生什么呢?我们猜一下,可能有两个问题: 编译器会 ...

  2. Go 嵌入类型

    文章转载地址:https://www.flysnow.org/2017/04/06/go-in-action-go-embedded-type.html 嵌入类型或嵌套类型,这是一种可以把已有类型的声 ...

  3. Swift 语言附注 类型

    本页包括内容: 类型注解(Type Annotation) 类型标识符(Type Identifier) 元组类型(Tuple Type) 函数类型(Function Type) 数组类型(Array ...

  4. 生成跨语言的类型声明和接口绑定的工具(Djinni )

    Djinni 是一个用来生成跨语言的类型声明和接口绑定的工具,主要用于 C++ 和 Java 以及 Objective-C 间的互通. 示例接口定义文件: # Multi-line comments ...

  5. C语言指针类型 强制转换

    关于C语言指针类型 强制转换  引用一篇文章: C语言中,任何一个变量都必须占有一个地址,而这个地址空间内的0-1代码就是这个变量的值.不同的数据类型占有的空间大小不一,但是他们都必须有个地址,而这个 ...

  6. 如何用一个语句判断一个整数是不是二的整数次幂——从一道简单的面试题浅谈C语言的类型提升(type promotion)

    最近招聘季,看JULY大哥的面试100题时,碰到这么一个扩展问题: 如何用一个语句判断一个整数是不是二的整数次幂?(此题在编程之美也有) easy, 2的整数次幂的二进制形式只有一个1,只要用i和i- ...

  7. c语言的类型、运算符与表达式

    title: 2017-10-17c语言的类型.运算符与表达式 tags: c程序设计语言 grammar_cjkRuby: true --- 1.1 数据类型 char 字符型,一个字节 int 整 ...

  8. 3. Go语言基本类型

    Go语言基本类型如下: bool string 数值类型 (int8, int16, int32, int64, int, uint8, uint16, uint32, uint64, uint, f ...

  9. Java下的框架编程(反射,泛型,元数据,CGLib,代码动态生成,AOP,动态语言嵌入)

    Java 虽然没有动态语言般暴起,但仍然天连天,水接水的生出好多框架技术---反射(reflection),泛型(generics),元数据(annotation),proxies(proxy/cgl ...

随机推荐

  1. Android TV端的(RecyclerView)水平滚动焦点错乱问题

    package com.hhzt.iptv.ui.customview; import android.content.Context;import android.content.res.Typed ...

  2. 微信小程序(一),授权页面搭建

    wxml代码如下: <!--pages/index2/index2.wxml--> <view class="index2Container"> <i ...

  3. Netty学习笔记(四) 简单的聊天室功能之服务端开发

    前面三个章节,我们使用了Netty实现了DISCARD丢弃服务和回复以及自定义编码解码,这篇博客,我们要用Netty实现简单的聊天室功能. Ps: 突然想起来大学里面有个课程实训,给予UDP还是TCP ...

  4. idea上使用maven入门(二)——本地仓库以及使用maven

    本地仓库: 首先创建完一个项目之后,点击左上角file->setting(建一个文件夹repository,建议创建到maven的外面,主要如果maven需要换版本,方便管理)如下图: ​ ma ...

  5. 搭建MHA时 yum 安装perl模块提示 baseurl 错误

    今天在搭建MySQL MHA  安装MHA node所需的perl模块(DBD:mysql)时遇到了一个小的错误,如果思路不对的话,还是产生不少麻烦. 现梳理记录下来. 问题现象 执行的命令 yum ...

  6. Linux LVM学习总结——Insufficient Free Extents for a Logical Volume

    如下所示,在创建LV的时候,偶尔会遇到"Volume group "xxxx" has insufficient free space (xxxx extents): x ...

  7. 实验吧逆向catalyst-system Writeup

    下载之后查看知道为ELF文件,linux中执行之后发现很慢: 拖入ida中查看发现有循环调用 sleep 函数: 这是已经改过了,edit -> patch program -> chan ...

  8. windows拿到cmd权限之后常用命令

    whoami    // 查看当前用户名称 ipconfig    // 查看本机ip信息,可加 /all 参数 netstat -ano // 查看端口清况 dir c:\  // 查看目录 typ ...

  9. OpenGL实例:三角形

    OpenGL实例:三角形 作者:凯鲁嘎吉 - 博客园 http://www.cnblogs.com/kailugaji/ 更多请查看:计算机图形学 1. 三角形的旋转 #include <GL/ ...

  10. 我的第一个python web开发框架(33)——接口代码重构

    前面ORM模块我们已经完成了开发,接下来要做的就是对项目代码进行重构了.因为对底层数据库操作模块(db_helper.py)进行了改造,之前项目的接口代码全都跑不起来了. 在写ORM模块时,我们已经对 ...