GO方法与接口
Go语言没有沿袭传统面向对象编程中的诸多概念,比如继承、虚函数、构造函数和析构函数、隐藏的this指针等。
方法
Go 语言中同时有函数和方法。方法就是一个包含了接受者(receiver)的函数,receiver可以是内置类型或者结构体类型的一个值或者是一个指针。所有给定类型的方法属于该类型的方法集。
如下面的这个例子,定义了一个新类型Integer,它和int一样,只是为它内置的int类型增加了个新方法Less()

type Integer int
func (a Integer) Less(b Integer) bool {
return a < b
}
func main() {
var a Integer = 1
if a.Less(2) {
fmt.Println("less then 2")
}
}

可以看出,Go语言在自定义类型的对象中没有C++/Java那种隐藏的this指针,而是在定义成员方法时显式声明了其所属的对象。
method的语法如下:
func (r ReceiverType) funcName(parameters) (results)
当调用method时,会将receiver作为函数的第一个参数:
funcName(r, parameters);
所以,receiver是值类型还是指针类型要看method的作用。如果要修改对象的值,就需要传递对象的指针。
指针作为Receiver会对实例对象的内容发生操作,而普通类型作为Receiver仅仅是以副本作为操作对象,并不对原实例对象发生操作。

func (a *Ingeger) Add(b Integer) {
*a += b
}
func main() {
var a Integer = 1
a.Add(3)
fmt.Println("a =", a) // a = 4
}

如果Add方法不使用指针,则a返回的结果不变,这是因为Go语言函数的参数也是基于值传递。
注意:当方法的接受者是指针时,即使用值类型调用那么方法内部也是对指针的操作。
之前说过,Go语言没有构造函数的概念,通常使用一个全局函数来完成。例如:

func NewRect(x, y, width, height float64) *Rect {
return &Rect{x, y, width, height}
}
func main() {
rect1 := NewRect(1,2,10,20)
fmt.Println(rect1.width)
}

匿名组合
Go语言提供了继承,但是采用了组合的语法,我们将其称为匿名组合,例如:

type Base struct {
name string
}
func (base *Base) Set(myname string) {
base.name = myname
}
func (base *Base) Get() string {
return base.name
}
type Derived struct {
Base
age int
}
func (derived *Derived) Get() (nm string, ag int) {
return derived.name, derived.age
}
func main() {
b := &Derived{}
b.Set("sina")
fmt.Println(b.Get())
}

例子中,在Base类型定义了get()和set()两个方法,而Derived类型继承了Base类,并改写了Get()方法,在Derived对象调用Set()方法,会加载基类对应的方法;而调用Get()方法时,加载派生类改写的方法。
组合的类型和被组合的类型包含同名成员时, 会不会有问题呢?可以参考下面的例子:

type Base struct {
name string
age int
}
func (base *Base) Set(myname string, myage int) {
base.name = myname
base.age = myage
}
type Derived struct {
Base
name string
}
func main() {
b := &Derived{}
b.Set("sina", 30)
fmt.Println("b.name =",b.name, "\tb.Base.name =", b.Base.name)
fmt.Println("b.age =",b.age, "\tb.Base.age =", b.Base.age)
}

值语义和引用语义
值语义和引用语义的差别在于赋值,比如
b = a
b.Modify()
如果b的修改不会影响a的值,那么此类型属于值类型;如果会影响a的值,那么此类型是引用类型。
Go语言中的大多数类型都基于值语义,包括:
- 基本类型,如byte、int、bool、float32、string等;
- 复合类型,如arry、struct、pointer等;
C语言中的数组比较特别,通过函数传递一个数组的时候基于引用语义,但是在结构体定义数组变量的时候基于值语义。而在Go语言中,数组和基本类型没有区别,是很纯粹的值类型,例如:
var a = [3] int{1,2,3}
var b = a
b[1]++
fmt.Println(a, b) // [1 2 3] [1 3 3]
从结果看,b=a赋值语句是数组内容的完整复制,要想表达引用,需要用指针:
var a = [3] int{1,2,3}
var b = &a // 引用语义
b[1]++
fmt.Println(a, b) // [1 3 3] [1 3 3]
接口
Interface 是一组抽象方法(未具体实现的方法/仅包含方法名参数返回值的方法)的集合,如果实现了 interface 中的所有方法,即该类/对象就实现了该接口。
Interface 的声明格式:
type interfaceName interface {
//方法列表
}
Interface 可以被任意对象实现,一个类型/对象也可以实现多个 interface;
interface的变量可以持有任意实现该interface类型的对象。
如下面的例子:

package main
import "fmt"
type Human struct {
name string
age int
phone string
}
type Student struct {
Human //匿名字段
school string
loan float32
}
type Employee struct {
Human //匿名字段
company string
money float32
}
//Human实现SayHi方法
func (h Human) SayHi() {
fmt.Printf("Hi, I am %s you can call me on %s\n", h.name, h.phone)
}
//Human实现Sing方法
func (h Human) Sing(lyrics string) {
fmt.Println("La la la la...", lyrics)
}
//Employee重载Human的SayHi方法
func (e Employee) SayHi() {
fmt.Printf("Hi, I am %s, I work at %s. Call me on %s\n", e.name,
e.company, e.phone)
}
// Interface Men被Human,Student和Employee实现
// 因为这三个类型都实现了这两个方法
type Men interface {
SayHi()
Sing(lyrics string)
}
func main() {
mike := Student{Human{"Mike", 25, "222-222-XXX"}, "MIT", 0.00}
paul := Student{Human{"Paul", 26, "111-222-XXX"}, "Harvard", 100}
sam := Employee{Human{"Sam", 36, "444-222-XXX"}, "Golang Inc.", 1000}
tom := Employee{Human{"Tom", 37, "222-444-XXX"}, "Things Ltd.", 5000}
//定义Men类型的变量i
var i Men
//i能存储Student
i = mike
fmt.Println("This is Mike, a Student:")
i.SayHi()
i.Sing("November rain")
//i也能存储Employee
i = tom
fmt.Println("This is tom, an Employee:")
i.SayHi()
i.Sing("Born to be wild")
//定义了slice Men
fmt.Println("Let's use a slice of Men and see what happens")
x := make([]Men, 3)
//这三个都是不同类型的元素,但是他们实现了interface同一个接口
x[0], x[1], x[2] = paul, sam, mike
for _, value := range x{
value.SayHi()
}
}

空接口
空interface(interface{})不包含任何的method,正因为如此,所有的类型都实现了空interface。空interface对于描述起不到任何的作用(因为它不包含任何的method),但是空interface在我们需要存储任意类型的数值的时候相当有用,因为它可以存储任意类型的数值。它有点类似于C语言的void*类型。

// 定义a为空接口
var a interface{}
var i int = 5
s := "Hello world"
// a可以存储任意类型的数值
a = i
a = s

interface的变量里面可以存储任意类型的数值(该类型实现了interface),那么我们怎么反向知道这个interface变量里面实际保存了的是哪个类型的对象呢?目前常用的有两种方法:switch测试、Comma-ok断言。
switch测试如下:

type Element interface{}
type List [] Element
type Person struct {
name string
age int
}
//打印
func (p Person) String() string {
return "(name: " + p.name + " - age: "+strconv.Itoa(p.age)+ " years)"
}
func main() {
list := make(List, 3)
list[0] = 1 //an int
list[1] = "Hello" //a string
list[2] = Person{"Dennis", 70}
for index, element := range list{
switch value := element.(type) {
case int:
fmt.Printf("list[%d] is an int and its value is %d\n", index, value)
case string:
fmt.Printf("list[%d] is a string and its value is %s\n", index, value)
case Person:
fmt.Printf("list[%d] is a Person and its value is %s\n", index, value)
default:
fmt.Println("list[%d] is of a different type", index)
}
}
}

如果使用Comma-ok断言的话:

func main() {
list := make(List, 3)
list[0] = 1 // an int
list[1] = "Hello" // a string
list[2] = Person{"Dennis", 70}
for index, element := range list {
if value, ok := element.(int); ok {
fmt.Printf("list[%d] is an int and its value is %d\n", index, value)
} else if value, ok := element.(string); ok {
fmt.Printf("list[%d] is a string and its value is %s\n", index, value)
} else if value, ok := element.(Person); ok {
fmt.Printf("list[%d] is a Person and its value is %s\n", index, value)
} else {
fmt.Printf("list[%d] is of a different type\n", index)
}
}
}

嵌入接口
正如struct类型可以包含一个匿名字段,interface也可以嵌套另外一个接口。
如果一个interface1作为interface2的一个嵌入字段,那么interface2隐式的包含了interface1里面的method。
GO方法与接口的更多相关文章
- C#属性-索引器-里氏替换-多态-虚方法-抽象-接口-泛型-
1.属性 //属性的2种写法 public class person { private string _name; public string Name { get { return _name; ...
- GoLang之方法与接口
GoLang之方法与接口 Go语言没有沿袭传统面向对象编程中的诸多概念,比如继承.虚函数.构造函数和析构函数.隐藏的this指针等. 方法 Go 语言中同时有函数和方法.方法就是一个包含了接受者的函数 ...
- jbuilder的set!方法重构接口
https://github.com/rails/jbuilder 的set!方法重构接口, 因为grape没法使用 jBuilder 的缓存,所以直接用 Rails 写 API (1)多个图片 i ...
- 使用 highchart 绘制柱状图的通用方法与接口
本文给出使用 highchart 绘制柱状图的通用方法与接口, 只要指定相应的数据结构和配置, 就可以直接拿来使用. 一. 数据结构与基本接口 一般绘制图形, 会涉及到较复杂的数据结构, 比如使 ...
- JAVAEE——Mybatis第一天:入门、jdbc存在的问题、架构介绍、入门程序、Dao的开发方法、接口的动态代理方式、SqlMapConfig.xml文件说明
1. 学习计划 第一天: 1.Mybatis的介绍 2.Mybatis的入门 a) 使用jdbc操作数据库存在的问题 b) Mybatis的架构 c) Mybatis的入门程序 3.Dao的开发方法 ...
- 初识 go 语言:方法,接口及并发
目录 方法,接口及并发 方法 接口 并发 信道 结束语 前言: go语言的第四篇文章,主要讲述go语言中的方法,包括指针,结构体,数组,切片,映射,函数闭包等,每个都提供了示例,可直接运行. 方法,接 ...
- Mock Server 实现post方法的接口(三)
Mock Server 实现post方法的接口(三) 1.mock server实现的接口,当request中未设置"method"时,会自动将所有method试一次,所以一定要指 ...
- mock server 实现get方法的接口(二)
mock server 实现get方法的接口(二) 下面是实现查询品牌的接口demo: 1.当response数据量小的时候,可以直接使用json, mock会自动设置headers为applicat ...
- Go 语言中的方法,接口和嵌入类型
https://studygolang.com/articles/1113 概述 在 Go 语言中,如果一个结构体和一个嵌入字段同时实现了相同的接口会发生什么呢?我们猜一下,可能有两个问题: 编译器会 ...
- Go 入门 - 方法和接口
方法和接口 方法的接受者 Go中没有类,取而代之的是在结构体上定义的方法 为了将方法(函数)绑定在某一类结构体上,我们在定义函数(方法)时引入"接受者"的概念. 方法接受者在它自己 ...
随机推荐
- java开发环境配置(windows下JDK7+tomcat7)
參考原文:http://www.cnblogs.com/goto/archive/2012/11/16/2772683.html http://www.cnblogs.com/feilong35407 ...
- 数字电路基本概念 —— fan-in/fan-out
0. 从模拟电路到数字电路 数字电路抗干扰能力强: 模拟电路会随着信号的传输而放大,这是因为模拟电路中信号几乎完全将真实信号按比例表现为电压或者电流的形式: 模拟电路是数字电路的基础 74LS283 ...
- 我是如何进行code review的
众所周知,代码审查是软件开发过程中十分重要的环节,楼主结合自己的实际工作经验,和大家分享一下在实际工作中代码审查是如何开展的, 笔者水平有限,若有错误和纰漏,还请大家指正. 代码审查的阻力 我想不通公 ...
- ICO图标在线生成,php生成ICO图标在线制作源码
我们做web系统的时候,每个浏览器的tab这里都会有一个图标,这个图标叫favicon图标,favicon.ico文件放在系统的根目录 如果程序员没有ICO制作工具,那么要如何生成图标呢?可以用程序来 ...
- 树莓派的rc.local档(设置开机)
为了树莓派执行命令或程序时启动.需要被添加到顺序rc.local档.这是为那些谁执行后,直接要权力树莓派没有配置.或者不希望每次都手动启动该程序很实用. 的方法是使用cron和crontab. EDI ...
- VC++实现Vista和Win7系统低权限程序向高权限程序发消息
Windows 7已经隆重发布,但是很多程序员已经通过RTM等版本尝到了Windows 7的甜处.那么在Windows 7下用户界面特权隔离,将是本文我们介绍的重点. 我们介绍了操作系统服务的Sess ...
- LaTeX —— 特殊符号与数学字体
1. 特殊符号 ℓ(\ell):用于和大小的 I 和 数字 1 相区分 R(\Re) ∇(\nabla):微分算子 2. 数学字体 mathbb:blackboard bold,黑板粗体 mathca ...
- 通过控制台查看电脑中.net framework的版本
cmd打开控制台之后输入以下命令reg query "HKLM\Software\Microsoft\NET Framework Setup\NDP" /s /v version ...
- 【C#】获取任意文件的缩略图
原文:[C#]获取任意文件的缩略图 因为用shell取缩略图时,对于损坏的文件,读出来的图有黑边,所以就诞生了以下方法,不过这个效率要比用shell取的低3-4倍. 1.添加类WindowsThumb ...
- Linux 下蓝牙bluez分析及使用 (1)
蓝牙耳机的使用 由于Linux下蓝牙使用不及Windows下直观,致使使用时会出现一些小问题.虽然是小问题,但是由于普通的操作都具有顺序性,前面的中断了,后面的哪怕再简单,也无法继续了.正好近期工作与 ...