go定义接口以及类怎么使用接口

多态是指代码可以根据类型的具体实现采取不同行为的能力。如果一个类型实现了某个接口,所有使用这个接口的地方,都可以支持这种类型的值。

  • 接口是用来定义行为的类型。这些被定义的行为不由接口直接实现,而是通过方法由用户定义的类型实现。如果用户定义的类型实现了某个接口类型声明的一组方法,那么这个用户定义的类型的值就可以赋给这个接口类型的值。这个赋值会把用户定义的类型的值存入接口类型的值。对接口值方法的调用会执行接口值里存储的用户定义的类型的值对应的方法。因为任何用户定义的类型都可以实现任何接口,所以对接口值方法的调用自然就是一种多态。

下面将创建一个用户定义结构体并实现一个发送接口:

package main

import "fmt"

// 定义一个notifier接口
// 通知类行为的一个接口
type notifier interface {
notify()
} // 定义一个用户类
type user struct {
name string
email string
} // nofity是使用指针接收者实现的方法
func (u *user) notify() {
fmt.Print("发送一条邮件给%s<%s>", u.name, u.email)
} func main() {
// 创建一个用户并复制
user := user{"小明", "1001**@qq.com"}
sendNotification(&user)
} func sendNotification(n notifier) {
n.notify()
}

注意:这里传递给sendNotification方法的用户定义结构体值user,是使用引用的方式传递的。因为类在实现接口的时候传递的参数是引用类型:(u *user),如果你是使用值传递的话,编辑器会报错。

./demo.go:25:18: cannot use user (type user) as type notifier in argument to sendNotification:
user does not implement notifier (notify method has pointer receiver)

进一步探索新问题,为什么上述使用值不行,使用引用可以呢?

如果你把是实现接口的传递参数改成值的形式而不是引用,你将会发现有所不同

// nofity是使用指针接收者实现的方法
func (u user) notify() {
fmt.Print("发送一条邮件给%s<%s>", u.name, u.email)
}

// 创建一个用户并复制
user := user{"小明", "1001**@qq.com"}
sendNotification(user)
sendNotification(&user)

你将会发现,使用引用的方式调用跟使用值的方式调用,编译器都不会报错,这是为什么?

  • 因为底层实现是如果使用指针来实现一个接口(u *user),那么只有指向那个类型(user)的指针才能实现对应的接口。
  • 如果使用值来实现一个接口,那么那个类型(user)的值和指针都能够实现对应的接口。

注意:使用指针实现接口和使用值实现接口有个区别在于,指针是指向内存同一块地址的,所以通过指针传递的参数,在函数体内执行结构体的改变会影响函数外的用户类型值,而使用值传递则不会 ,这也是在使用指针和使用值的不同场景选择的一个区别其中之一。

使用值:

package main

import "fmt"

// 定义一个notifier接口
// 通知类行为的一个接口
type notifier interface {
notify()
} // 定义一个用户类
type user struct {
name string
email string
} // nofity是使用指针接收者实现的方法
func (u user) notify() {
u.name = "小红"
fmt.Print("发送一条邮件给%s<%s>", u.name, u.email)
} func main() {
// 创建一个用户并复制
user := user{"小明", "1001**@qq.com"}
//sendNotification(user)
sendNotification(&user) // 小明
fmt.Println(user.name)
sendNotification(user) // 小明
fmt.Println(user.name) } func sendNotification(n notifier) {
n.notify()
}

使用指针:

package main

import "fmt"

// 定义一个notifier接口
// 通知类行为的一个接口
type notifier interface {
notify()
} // 定义一个用户类
type user struct {
name string
email string
} // nofity是使用指针接收者实现的方法
func (u *user) notify() {
u.name = "小红"
fmt.Print("发送一条邮件给%s<%s>", u.name, u.email)
} func main() {
// 创建一个用户并复制
user := user{"小明", "1001**@qq.com"}
//sendNotification(user)
sendNotification(&user) // 小红
fmt.Println(user.name) } func sendNotification(n notifier) {
n.notify()
}

go定义接口以及类怎么使用接口的更多相关文章

  1. Java基础之Comparable接口, Collections类,Iterator接口,泛型(Generic)

    一.Comparable接口, Collections类 List的常用算法: sort(List); 排序,如果需要对自定义的类进行排序, 那就必须要让其实现Comparable接口, 实现比较两个 ...

  2. Java 私有接口 【类中嵌套接口】

    1.前言 接口十分常用,能规范实现类的命名 和 实现多个实现类的向上转型成统一类型 ,但是接口的修饰符只能是 public吗? 当然不是,可以是private , 难道是像这样? 显然不可以,已经报错 ...

  3. PHP类继承、接口继承关系概述

    PHP类继承: PHP类不支持多继承,也就是子类只能继承一个父类,但是支持多层次继承,比如: class frist{ public function __construct(){ echo &quo ...

  4. Eclipse如何查看接口实现类快捷键

    1.找到要打开的接口类 2.双击接口名选中 3.按Ctrl+T打开接口实现类 以List接口为例,如下所示

  5. python接口自动化(五)--接口测试用例和接口测试报告模板(详解)

    简介 当今社会在测试领域,接口测试已经越来越多的被提及,被重视,而且现在好多招聘信息要对接口测试提出要求.区别于传统意义上的系统级别测试,很多测试人员在接触到接口测试的时候,也许对测试执行还可以比较顺 ...

  6. C#的接口基础教程之四 访问接口

    对接口成员的访问 对接口方法的调用和采用索引指示器访问的规则与类中的情况也是相同的.如果底层成员的命名与继承而来的高层成员一致,那么底层成员将覆盖同名的高层成员.但由于接口支持多继承,在多继承中,如果 ...

  7. 调试接口,返回的json数据,我定义了一个类,用来序列化,其中有一个字段定义为string 然后序列化的时候报错

    调试接口,返回的json数据,我定义了一个类,用来序列化,其中有一个字段定义为string 然后序列化的时候报错 在需要解析的类型类上加上声明 eg:

  8. Spring只定义接口自动代理接口实现类

    能够扫描到包 @ComponentScan("org.zxp.esclientrhl") ESCRegistrar类主要实现ImportBeanDefinitionRegistra ...

  9. python定义接口继承类

    zxq547 python定义接口继承类invalid syntax解决办法 1 2 3 4 5 6 7 class s_all(metaclass=abc.ABCMeta):     #python ...

随机推荐

  1. c语言编程基础入门必备知识

    数据类型 基本数据类型 类型名称说明char字符类型存放字符的ASCII码int整型存放有符号整数short短整型存放有符号整数long长整型存放有符号整数long long存放有符号整数float单 ...

  2. Nginx(三):Linux环境(Ubuntu)下Nginx的安装

    Nginx 是一位俄罗斯人 Igor Sysoev(伊戈尔·塞索斯夫)编写的一款高性能HTTP和反向代理服务器. Nginx 主要是有C编写的,安装Nginx需要GCC编译器(GNU Compiler ...

  3. 个人宽带如何开启IPv6网络访问

    IPv6是大势所趋,就在前段时间湖南联通发布公告,对家庭宽带提供 IPv6 地址,不再提供 IPv4地址,那本文就介绍 个人宽带如何开启 IPv6网络访问. 湖南联通停止向普通家庭宽带用户提供公网 I ...

  4. Android DataBinding使用详解

    简介 DataBinding是一个自动绑定UI的框架. 使用DataBinding需要在app根目录的build.gradle文件中加入DataBinding配置: android { .... da ...

  5. OpenAPITools 实践

    OpenAPITools 可以依据 REST API 描述文件,自动生成服务端桩(Stub)代码.客户端 SDK 代码,及文档等.其是社区版的 Swagger ,差异可见:OpenAPI Genera ...

  6. Java 17 新功能介绍(LTS)

    点赞再看,动力无限.Hello world : ) 微信搜「程序猿阿朗 」. 本文 Github.com/niumoo/JavaNotes 和 未读代码博客 已经收录,有很多知识点和系列文章. Jav ...

  7. Oracle SQL注入 总结

    0x00 Oracle基础 Oracle 基本使用 什么是Oracle数据库? Oracle公司目前是世界上最大的软件提供商之一,与它并列的还有 Microsoft与 Adode.并且随着 Oracl ...

  8. redis 内存划分

    1.数据:作为数据库,数据是最主要的部分,这部分占用的内存会被统计在used_memory中 2.进程内存:redis主进程本身运行需要占用的内存,这部分内存会被统计在used_memory_rss中 ...

  9. c++学习笔记(五)

    数组作为函数参数 定义 数组可以作为函数的参数使用,进行数据传送. 数组用作函数参数有两种形式,一种是把数组元素(下标变量)作为实参使用:另一种是把数组名作为函数的形参和实参使用. 1.数组元素作为函 ...

  10. silky微服务框架服务注册中心介绍

    目录 服务注册中心简介 服务元数据 主机名称(hostName) 服务列表(services) 终结点 时间戳 使用Zookeeper作为服务注册中心 使用Nacos作为服务注册中心 使用Consul ...