• linkedu视频
  • 平面设计
  • 电脑入门
  • 操作系统
  • 办公应用
  • 电脑硬件
  • 动画设计
  • 3D设计
  • 网页设计
  • CAD设计
  • 影音处理
  • 数据库
  • 程序设计
  • 认证考试
  • 信息管理
  • 信息安全
菜单
linkedu.com
  • 网页制作
  • 数据库
  • 程序设计
  • 操作系统
  • CMS教程
  • 游戏攻略
  • 脚本语言
  • 平面设计
  • 软件教程
  • 网络安全
  • 电脑知识
  • 服务器
  • 视频教程
  • vbs
  • DOS/BAT
  • hta/htc
  • python
  • perl
  • VBA
  • ColdFusion
  • ruby
  • PowerShell
  • Lua
  • Golang
  • linux shell
您的位置:首页 > 脚本语言 >Golang > Go语言中的方法、接口和嵌入类型详解

Go语言中的方法、接口和嵌入类型详解

作者:junjie 字体:[增加 减小] 来源:互联网

junjie 通过本文主要向大家介绍了go语言接口,go语言,go语言环境搭建,go语言程序设计,let it go 25种语言等相关知识,希望对您有所帮助,也希望大家支持linkedu.com www.linkedu.com

概述

在 Go 语言中,如果一个结构体和一个嵌入字段同时实现了相同的接口会发生什么呢?我们猜一下,可能有两个问题:

1.编译器会因为我们同时有两个接口实现而报错吗?
2.如果编译器接受这样的定义,那么当接口调用时编译器要怎么确定该使用哪个实现?

在写了一些测试代码并认真深入的读了一下标准之后,我发现了一些有意思的东西,而且觉得很有必要分享出来,那么让我们先从 Go 语言中的方法开始说起。

方法

Go 语言中同时有函数和方法。一个方法就是一个包含了接受者的函数,接受者可以是命名类型或者结构体类型的一个值或者是一个指针。所有给定类型的方法属于该类型的方法集。

下面定义一个结构体类型和该类型的一个方法:
type User struct {
  Name  string
  Email string
}

func (u User) Notify() error
</div>

首先我们定义了一个叫做 User 的结构体类型,然后定义了一个该类型的方法叫做 Notify,该方法的接受者是一个 User 类型的值。要调用 Notify 方法我们需要一个 User 类型的值或者指针:

// User 类型的值可以调用接受者是值的方法
damon := User{"AriesDevil", "ariesdevil@xxoo.com"}
damon.Notify()

// User 类型的指针同样可以调用接受者是值的方法
alimon := &User{"A-limon", "alimon@ooxx.com"}
alimon.Notify()
</div>

在这个例子中当我们使用指针时,Go 调整和解引用指针使得调用可以被执行。注意,当接受者不是一个指针时,该方法操作对应接受者的值的副本(意思就是即使你使用了指针调用函数,但是函数的接受者是值类型,所以函数内部操作还是对副本的操作,而不是指针操作,参见:http://play.golang.org/p/DBhWU0p1Pv)。

我们可以修改 Notify 方法,让它的接受者使用指针类型:

func (u *User) Notify() error
</div>

再来一次之前的调用(注意:当接受者是指针时,即使用值类型调用那么函数内部也是对指针的操作,参见:http://play.golang.org/p/SYBb4xPfPh):

// User 类型的值可以调用接受者是指针的方法
damon := User{"AriesDevil", "ariesdevil@xxoo.com"}
damon.Notify()

// User 类型的指针同样可以调用接受者是指针的方法
alimon := &User{"A-limon", "alimon@ooxx.com"}
alimon.Notify()
</div>

如果你不清楚到底什么时候该使用值,什么时候该使用指针作为接受者,你可以去看一下这篇介绍。这篇文章同时还包含了社区约定的接受者该如何命名。

接口

Go 语言中的接口很特别,而且提供了难以置信的一系列灵活性和抽象性。它们指定一个特定类型的值和指针表现为特定的方式。从语言角度看,接口是一种类型,它指定一个方法集,所有方法为接口类型就被认为是该接口。

下面定义一个接口:
type Notifier interface {
  Notify() error
}
</div>

我们定义了一个叫做 Notifier 的接口并包含一个 Notify 方法。当一个接口只包含一个方法时,按照 Go 语言的约定命名该接口时添加 -er 后缀。这个约定很有用,特别是接口和方法具有相同名字和意义的时候。

我们可以在接口中定义尽可能多的方法,不过在 Go 语言标准库中,你很难找到一个接口包含两个以上的方法。

实现接口

当涉及到我们该怎么让我们的类型实现接口时,Go 语言是特别的一个。Go 语言不需要我们显式的实现类型的接口。如果一个接口里的所有方法都被我们的类型实现了,那么我们就说该类型实现了该接口。

让我们继续之前的例子,定义一个函数来接受任意一个实现了接口 Notifier 的类型的值或者指针:
func SendNotification(notify Notifier) error {
  return notify.Notify()
}
</div>

SendNotification 函数调用 Notify 方法,这个方法被传入函数的一个值或者指针实现。这样一来一个函数就可以被用来执行任意一个实现了该接口的值或者指针的指定的行为。

用我们的 User 类型来实现该接口并且传入一个 User 类型的值来调用 SendNotification 方法:
func (u *User) Notify() error {
  log.Printf("User: Sending User Email To %s<%s>\n",
      u.Name,
      u.Email)
  return nil
}

func main() {
  user := User{
    Name:  "AriesDevil",
    Email: "ariesdevil@xxoo.com",
  }
 
  SendNotification(user)
}

// Output:
cannot use user (type User) as type Notifier in function argument:
User does not implement Notifier (Notify method has pointer receiver)
</div>

详细代码:http://play.golang.org/p/KG8-Qb7gqM

为什么编译器不考虑我们的值是实现该接口的类型?接口的调用规则是建立在这些方法的接受者和接口如何被调用的基础上。下面的是语言规范里定义的规则,这些规则用来说明是否我们一个类型的值或者指针实现了该接口:

1.类型 *T 的可调用方法集包含接受者为 *T 或 T 的所有方法集

这条规则说的是如果我们用来调用特定接口方法的接口变量是一个指针类型,那么方法的接受者可以是值类型也可以是指针类型。显然我们的例子不符合该规则,因为我们传入 SendNotification 函数的接口变量是一个值类型。

1.类型 T 的可调用方法集包含接受者为 T 的所有方法

这条规则说的是如果我们用来调用特定接口方法的接口变量是一个值类型,那么方法的接受者必须也是值类型该方法才可以被调用。显然我们的例子也不符合这条规则,因为我们 Notify 方法的接受者是一个指针类型。

语言规范里只有这两条规则,我通过这两条规则得出了符合我们例子的规则:

1.类型 T 的可调用方法集不包含接受者为 *T 的方法

我们碰巧赶上了我推断出的这条规则,所以编译器会报错。Notify 方法使用指针类型作为接受者而我们却通过值类型来调用该方法。解决办法也很简单,我们只需要传入 User 值的地址到 SendNotification 函数就好了:
func main() {
  user := &User{
    Name:  "AriesDevil",
    Email: "ariesdevil@xxoo.com",
  }
 
  SendNotification(user)
}

// Output:

您可能想查找下面的文章:

  • Go语言接口定义与用法示例
  • go语言接口用法实例分析
  • Go语言排序与接口实例分析
  • Go语言接口用法实例
  • Go语言中接口组合的实现方法
  • Go语言中的方法、接口和嵌入类型详解

相关文章

  • GO语言文件的创建与打开实例分析
  • go语言执行等待直到后台goroutine执行完成实例分析
  • Go语言Cookie用法分析
  • Golang极简入门教程(四):编写第一个项目
  • 使用os包和flag包实现读取main命令入参
  • Go语言中关闭带缓冲区的频道实例分析
  • Golang学习笔记(五):函数
  • 详解Golang编程中的常量与变量
  • GO语言标准错误处理机制error用法实例
  • Go语言使用字符串的几个技巧分享

文章分类

  • vbs
  • DOS/BAT
  • hta/htc
  • python
  • perl
  • VBA
  • ColdFusion
  • ruby
  • PowerShell
  • Lua
  • Golang
  • linux shell

最近更新的内容

    • Go语言中嵌入C语言的方法
    • 深入解析快速排序算法的原理及其Go语言版实现
    • Go语言中使用 buffered channel 实现线程安全的 pool
    • 简单了解Go语言中函数作为值以及函数闭包的使用
    • Go语言计算指定年月天数的方法
    • Go语言MD5加密用法实例
    • golang实现unicode转换为字符串string的方法
    • go语言通过管道连接两个命令行进程的方法
    • 简单讲解Go程序中使用MySQL的方法
    • Go语言编程中字符串切割方法小结

关于我们 - 联系我们 - 免责声明 - 网站地图

©2020-2025 All Rights Reserved. linkedu.com 版权所有