一.  go方法

go方法:在函数的func和函数名间增加一个特殊的接收器类型,接收器可以是结构体类型或非结构体类型。接收器可以在方法内部访问。创建一个接收器类型为Type的methodName方法。

func (t Type) methodName(parameter list) {
}

go引入方法的原因:

1)go不是纯粹的面向对象编程语言,而且Go不支持类。因此,基于类型的方法是一种实现和类相似行为的途径。

2)相同名字的方法可以定义在不同的类型上,而相同名字的函数不被允许。

方法调用

t.methodName(parameter list)

指针接收器与值接收器

区别:指针接收器的方法内部的改变对外可见,而值接收器不会改变方法外部的变量。

对于指针接收器&T Type而言,(&T).methodName与T.methodName等价。

匿名字段的方法

属于结构体的匿名字段的方法可以被直接调用,就好像这些方法是属于定义了匿名字段的结构体一样。

在方法中使用值接收器 与 在函数中使用值参数

当一个函数有一个值参数,它只能接受一个值参数。

当一个方法有一个值接收器,它可以接受值接收器和指针接收器。

package main

import "fmt"

type rectangle struct {
length int
width int
} func area(r rectangle){
fmt.Printf("Area Function result: %d\n", (r.length * r.width))
} func (r rectangle)area(){
fmt.Printf("Area method result: %d\n", (r.length * r.width))
} func main(){
r := rectangle{
length: ,
width: ,
} area(r)
r.area() p := &r
// area(p) // cannot use p (type *rectangle) as type rectangle in argument to area
p.area() //通过指针调用接收器
}

在方法中使用指针接收器 与 在函数中使用指针参数

函数使用指针参数只接受指针,而使用指针接收器的方法可以使用值接收器和指针接收器。

在非结构体上的方法

为了在一个类型上定义一个方法,方法的接收器类型定义和方法的定义应该在同一个包中。

对于内建类型,如int,应该在文件中创建一个类型别名,然后创建一个以该类型别名为接收器的方法。

二.  go接口

接口是方法(方法签名,method signature)的集合。当一个类型定义了接口中的所有方法,就称它实现了该接口。与OOP类似,接口定义了一个类型应该具有的方法,由该类型决定如何实现这些方法。

type myInterface interface{
method1()
method2()
}

接口调用

//interface definition
type VowelsFinder interface {
FindVowels() []rune
} type MyString string //MyString implements VowelsFinder
func (ms MyString) FindVowels() []rune {
var vowels []rune
for _, rune := range ms {
if rune == 'a' || rune == 'e' || rune == 'i' || rune == 'o' || rune == 'u' {
vowels = append(vowels, rune)
}
}
return vowels
} name := MyString("Sam Anderson")
var v VowelsFinder
v = name // possible since MyString implements VowelsFinder
fmt.Printf("Vowels are %c", v.FindVowels())

如果一个类型包含了接口中声明的所有方法,那么它就隐式地实现了 Go 接口

接口的内部表示

可以把接口看作内部的一个元组 (type, value)。 type 是接口底层的具体类型(Concrete Type),而 value 是具体类型的值。

type Test interface {
Tester()
} type MyFloat float64 func (m MyFloat) Tester() {
fmt.Println(m)
} func describe(t Test) {
fmt.Printf("Interface type %T value %v\n", t, t)
} func main() {
var t Test
f := MyFloat(89.7)
t = f
describe(t)
t.Tester()
}

输出:

Interface type main.myFloat value 89.7
89.7

空接口

没有包含方法的接口称为空接口。空接口表示为 interface{}。由于空接口没有方法,因此所有类型都实现了空接口。

当指定参数为空接口时,可以接收任意类型,那如何获取参数的值呢?  通过类型断言。 v, ok := p.(int),判定参数是否为int并获取参数值。

类型断言

类型断言用于提取接口的底层值(Underlying Value)。

在语法 i.(T) 中,接口 i 的具体类型是 T,该语法用于获得接口的底层值。

v, ok := i.(T)

如果 i 的具体类型是 T,那么 v 赋值为 i 的底层值,而 ok 赋值为 true。

如果 i 的具体类型不是 T,那么 ok 赋值为 false,v 赋值为 T 类型的零值,此时程序不会报错

类型选择(Type Switch)

类型选择用于将接口的具体类型与很多 case 语句所指定的类型进行比较。它与一般的 switch 语句类似。

类型断言的语法是 i.(type),获取接口的类型

还可以将一个类型和接口相比较。如果一个类型实现了接口,那么该类型与其实现的接口就可以互相比较。

type Describer interface {
Describe()
} type Person struct {
name string
age int
} func (p Person) Describe(){
fmt.Printf("%s is %d years old\n", p.name, p.age)
} func findType(i interface{}){
switch v := i.(type){
case Describer:
v.Describe()
default:
fmt.Printf("unknown type\n")
}
} func main(){
findType("wang")
p := Person{
name: "qing",
age: ,
} findType(p)
}
unknown type
qing is years old

在上面程序中,结构体 Person 实现了 Describer 接口。在第 19 行的 case 语句中,v 与接口类型 Describer 进行了比较。p 实现了 Describer,因此满足了该 case 语句,于是当程序运行到第 32 行的 findType(p) 时,程序调用了 Describe() 方法。

实现接口:指针接受者与值接受者

使用值接受者声明的方法,接口既可以用值来调用,也能用指针调用。

对于使用指针接受者的方法,必须用一个指针或者一个可取得地址的值(&method)来调用。但接口中存储的具体值(Concrete Value)并不能取到地址,对于编译器无法自动获取 a 的地址,于是程序报错。

type Describer interface {
Describe()
}
type Person struct {
name string
age int
} func (p Person) Describe() { // 使用值接受者实现
fmt.Printf("%s is %d years old\n", p.name, p.age)
} type Address struct {
state string
country string
} func (a *Address) Describe() { // 使用指针接受者实现
fmt.Printf("State %s Country %s", a.state, a.country)
} func main() {
var d1 Describer
p1 := Person{"Sam", }
d1 = p1
d1.Describe()
p2 := Person{"James", }
d1 = &p2
d1.Describe() var d2 Describer
a := Address{"Washington", "USA"} /* 如果下面一行取消注释会导致编译错误:
cannot use a (type Address) as type Describer
in assignment: Address does not implement
Describer (Describe method has pointer
receiver)
*/
//d2 = a d2 = &a // 这是合法的
// 因为在第 22 行,Address 类型的指针实现了 Describer 接口
d2.Describe()
}

接口的嵌套

type SalaryCalculator interface {
DisplaySalary()
} type LeaveCalculator interface {
CalculateLeavesLeft() int
} type EmployeeOperations interface {
SalaryCalculator
LeaveCalculator
}

接口的零值

接口的零值是 nil。对于值为 nil 的接口,其底层值(Underlying Value)和具体类型(Concrete Type)都为 nil。对于值为 nil 的接口,由于没有底层值和具体类型,当我们试图调用它的方法时,程序会产生 panic 异常。

Go接口最佳实践

1)倾向于使用小的接口定义,很多接口只包含一个方法。    如Reader,Writer,便于类型实现接口,方法太多,类型实现越麻烦。

2)较大的接口定义,可以由多个小接口定义组合而成。  即接口的嵌套。

3)只依赖于必要功能的最小接口。方法或函数的接口参数的范围或方法越小越好,这样便于参数的调用,和方法或函数被其他程序调用。

如func StoreData(reader Reader) error{},能传递Reader就不传递ReadWriter。

参考:Go 系列教程 —— 17. 方法     Golang tutorial series  英文原版

golang方法和接口的更多相关文章

  1. GoLang之方法与接口

    GoLang之方法与接口 Go语言没有沿袭传统面向对象编程中的诸多概念,比如继承.虚函数.构造函数和析构函数.隐藏的this指针等. 方法 Go 语言中同时有函数和方法.方法就是一个包含了接受者的函数 ...

  2. Golang 中的 面向对象: 方法, 类, 方法继承, 接口, 多态的简单描述与实现

    前言: Golang 相似与C语言, 基础语法与C基本一致,除了广受争议的 左花括号 必须与代码同行的问题, 别的基本差不多; 学会了C, 基本上万变不离其宗, 现在的高级语言身上都能看到C的影子; ...

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

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

  4. Go 语言入门(二)方法和接口

    写在前面 在学习 Go 语言之前,我自己是有一定的 Java 和 C++ 基础的,这篇文章主要是基于A tour of Go编写的,主要是希望记录一下自己的学习历程,加深自己的理解 Go 语言入门(二 ...

  5. Go语言_方法和接口

    方法和接口 本节课包含了方法和接口,可以用这种构造来定义对象及其行为. Go 作者组编写,Go-zh 小组翻译. https://tour.go-zh.org/methods/1 方法 Go 没有类. ...

  6. 带你学够浪:Go语言基础系列 - 10分钟学方法和接口

    文章每周持续更新,原创不易,「三连」让更多人看到是对我最大的肯定.可以微信搜索公众号「 后端技术学堂 」第一时间阅读(一般比博客早更新一到两篇) 对于一般的语言使用者来说 ,20% 的语言特性就能够满 ...

  7. C#属性-索引器-里氏替换-多态-虚方法-抽象-接口-泛型-

    1.属性 //属性的2种写法 public class person { private string _name; public string Name { get { return _name; ...

  8. jbuilder的set!方法重构接口

    https://github.com/rails/jbuilder  的set!方法重构接口, 因为grape没法使用 jBuilder 的缓存,所以直接用 Rails 写 API (1)多个图片 i ...

  9. 使用 highchart 绘制柱状图的通用方法与接口

    本文给出使用 highchart 绘制柱状图的通用方法与接口, 只要指定相应的数据结构和配置, 就可以直接拿来使用. 一.  数据结构与基本接口   一般绘制图形, 会涉及到较复杂的数据结构, 比如使 ...

随机推荐

  1. Session覆盖测试(要验证码提交到后续页面操作的 绕过去的场景)

    测试原理和方法 找回密码逻辑漏洞测试中也会遇到参数不可控的情况,比如要修改的用户名或者绑定 的手机号无法在提交参数时修改,服务端通过读取当前session会话来判断要修改密码的账 号,这种情况下能否对 ...

  2. nginx入门系列之安装与卸载

    目录 通过包管理器安装 安装nginx 卸载nginx 从源码编译安装 准备安装环境 执行编译安装 制作nginx免安装包 官方安装手册:https://nginx.org/en/docs/insta ...

  3. odoo self.ensure_one()

    源码: def ensure_one(self): """ Verifies that the current recorset holds a single recor ...

  4. Maven中dependencyManagement作用说明

    https://blog.csdn.net/helllochun/article/details/81564921 在Maven多模块的时候,管理依赖关系是非常重要的,各种依赖包冲突,查询问题起来非常 ...

  5. es内存不够

    8核32G 3台 ELS机器,当时只给es配置了8G内存,es的总体数据量大小将近30G(查看GET /_cat/shards?v)

  6. 《算法图解》全本PDF下载附百度云链接

    作者使用Python和图画来解释算法,找了好久才找到PDF版本,末尾附百度云链接~ 作者[美]Aditya Bhargava 译者袁国忠 类别 出版 / 非虚构 出版社人民邮电出版社 / 2017-0 ...

  7. CSS3弹性盒布局方式

    一.CSS3弹性盒子 弹性盒子是CSS3的一种新布局模式. CSS3 弹性盒( Flexible Box 或 flexbox),是一种当页面需要适应不同的屏幕大小以及设备类型时确保元素拥有恰当的行为的 ...

  8. Python入门 常量 注释 基础数据类型 用户输入 流程控制

    Python入门 一.常量 在Python中,不像其他语言有绝对的常量,修改会报错,在Python中有个约定俗成的规定--常量就是将变量名大写. 尽量保持不更改的一种量 , 这个常量有是干什么的呢 其 ...

  9. Java 的 WebSocket

    1. WebSocket 是什么 一言以蔽之,WebSocket允许服务器「主动」给浏览器发消息,如教程演示截图,服务器会主动推送比特币价格给浏览器. 2. 为什么要用 WebSocket 实时获取服 ...

  10. 阿里云负载均衡SLB上用免费的Let's Encrypt的SSL证书

    Let's Encrypt是很火的一个免费SSL证书发行项目,自动化发行证书,证书有90天的有效期.Let's Encrypt已经发布了工具certbot,用此工具生成证书.证书续期非常简单. 以下是 ...