GoLang之方法与接口

GoLang之方法与接口

 

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 {Baseage 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 stringage int
}func (base *Base) Set(myname string, myage int) {base.name = mynamebase.age = myage
}type Derived struct {Basename 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 mainimport "fmt"type Human struct {name stringage intphone string}type Student struct {Human //匿名字段school stringloan float32}type Employee struct {Human //匿名字段company stringmoney 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类型的变量ivar i Men//i能存储Studenti = mike    fmt.Println("This is Mike, a Student:")i.SayHi()i.Sing("November rain")//i也能存储Employeei = tomfmt.Println("This is tom, an Employee:")i.SayHi()i.Sing("Born to be wild")//定义了slice Menfmt.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, mikefor _, value := range x{value.SayHi()}}

 

空接口

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

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

 

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

 

switch测试如下:

type Element interface{}
type List [] Elementtype Person struct {name stringage 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 stringlist[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 intlist[1] = "Hello" // a stringlist[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。

 

 

 

参考文档:

http://se77en.cc/2014/05/05/methods-interfaces-and-embedded-types-in-golang/

http://se77en.cc/2014/05/04/choose-whether-to-use-a-value-or-pointer-receiver-on-methods/

 

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/263423.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

孙继海化装

于输得太惨&#xff0c;中国球员怕回国被球迷打&#xff0c;孙继海决定化装成“乞丐”。化好之后遇到一个老太太&#xff0c;他想看看自己化装的效果&#xff0c;就给了老太太100块钱&#xff0c;问&#xff1a;“你知道我是谁吗&#xff1f;”老太太看了看说&#xff1a;“你是…

sql 时间函数

1. 当前系统日期、时间 select getdate() 2. dateadd 在向指定日期加上一段时间的基础上&#xff0c;返回新的 datetime 值 例如&#xff1a;向日期加上2天 select dateadd(day,2,’2004-10-15′) –返回&#xff1a;2004-10-17 00:00:00.000 3. datediff 返回跨两个指定日期的…

大数据——Hive学习笔记

具体代码可以参考&#xff1a; https://github.com/Ostrich5yw/java4BigData

Eclipse 常用快捷键

Eclipse 常用快捷键 快捷键 描述 编辑 Ctrl1 快速修复&#xff08;最经典的快捷键,就不用多说了&#xff0c;可以解决很多问题&#xff0c;比如import类、try catch包围等&#xff09; CtrlShiftF 格式化当前代码 CtrlShiftM 添加类的import导入 CtrlShiftO 组织类的…

[Story]狗尾草花园

不知道为什么&#xff0c;很多年过去&#xff0c;我却依然记得这个故事。很小的时候&#xff0c;大概四、五岁吧&#xff0c;在河滩上和几个姐姐&#xff0c;一起玩过家家。他们大概十三&#xff0c;四岁吧&#xff0c;反正比我大好多。分成两组&#xff0c;我在我们一组当然是…

UML各种图

转载自&#xff1a; https://www.cnblogs.com/jiangds/p/6596595.html UML&#xff08;Unified Modeling Language&#xff09;是一种统一建模语言&#xff0c;为面向对象开发系统的产品进行说明、可视化、和编制文档的一种标准语言。下面将对UML的九种图包图的基本概念进行介绍…

Interactive Reflection Editing (SIGGRAPH ASIA 09)

讓使用者可以將reflection做editing 以達到使用者想要的結果INPUT: a 3d scene大部分是針對卡通等NPR的場景 對於reflection做editing利用shader也可以控制reflection這篇可以讓使用者做更動沒有使用BRDF做reflection的計算转载于:https://www.cnblogs.com/GameJan/archive/201…

大数据——Hive学习笔记(配置)

具体代码可以参考&#xff1a; https://github.com/Ostrich5yw/java4BigData

CSDN-markdown编辑器语法——字体、字号与颜色

Markdown是一种可以使用普通文本编辑器编写的标记语言&#xff0c;通过类似HTML的标记语法&#xff0c;它可以使普通文本内容具有一定的格式。但是它本身是不支持修改字体、字号与颜色等功能的&#xff01; CSDN-markdown编辑器是其衍生版本&#xff0c;扩展了Markdown的功能&a…

思科携手中兴掌握3G话语权 剑指华为3COM组合

思科携手中兴掌握3G话语权 剑指华为3COM组合 中国电信市场又迎来了一次中外巨头的牵手。昨日,思科系统公司和中兴通讯股份有限公司共同宣布,双方已签署了一份战略合作协议,将进行范围广泛的合作。这也是林正刚上任思科系统中国总裁后,祭出的首个“中国攻略”。 根据协议,两家公…

JS服务器端开发基础篇(Array.slice方法和splice方法)

Array.slice方法和splice方法在众多的JS数组中属于比较复杂的一个方法&#xff0c;而且容易记混。搜索网络上很多资料都没有发现系统的总结。特别归纳如下&#xff0c;不完全处还希望各位批评指正。一、slice方法格式&#xff1a;arrayObj.slice(start, [end])功能&#xff1a;…

HashMap(摘)

1.HashMap简介 HashMap基于哈希表的Map接口实现&#xff0c;是以key-value存储形式存在。&#xff08;除了不同步和允许使用 null 之外&#xff0c;HashMap 类与 Hashtable 大致相同。)HashMap 的实现不是同步的&#xff0c;这意味着它不是线程安全的。它的key、value都可以为n…

LeetCode—274. H 指数

274. H 指数 题目描述&#xff1a; 给你一个整数数组 citations &#xff0c;其中 citations[i] 表示研究者的第 i 篇论文被引用的次数。计算并返回该研究者的 h 指数。 根据维基百科上 h 指数的定义&#xff1a;h 代表“高引用次数”&#xff0c;一名科研人员的 h指数是指他…

【创业】创业团队的那些事(二)

在上一篇&#xff08;创业团队的那些事&#xff08;一&#xff09;&#xff09;从邮件中看到很多博友的评论&#xff0c;很行赏他们的观点&#xff0c;关于创业团队&#xff0c;我们都有说不完的理论&#xff0c;想不完的创意&#xff0c;干不完的事情&#xff0c;永远无法预知…

日常经典用语、成语及谚语

cross your heart 你发誓       gate - crasher 不请自来的不速之客      take it easy 凡事看开些, 不要太冲动, 不要看得那么重       make yourself comfortable 不用约束 (招待客人时说的话)       you are all wet 你完全误会了       she …

JavaScript复制数组

转载于:https://blog.51cto.com/5880861/1651346

面向对象基础(一)

我想在这个园子里面的新人&#xff0c;还是"掌门人"&#xff0c;都对"面向对象"这几字非常的耳熟了或者有一定的了解。 但当一个初学都在学习面向对象的时候&#xff0c;会遇到一些瓶颈和麻烦&#xff0c;认为面向对象非常的难以理解。 那么本章节主要是让…

有哪些简单粗暴的logo设计方法?

Logo设计在设计的过程中要考虑很多问题&#xff0c;但是如果时间周期比较短&#xff0c;又要求快速出方案的时候&#xff0c;可以走一些捷径。 在设计logo之前要去了解公司的主营业务、公司规模、公司的名字、公司的主要产品针对的用户群体、甲方的个人偏好、公司原有VIS...这些…

大数据——Zookeeper学习笔记

具体代码可以参考&#xff1a; https://github.com/Ostrich5yw/java4BigData

事情在不断的解决中,想念巫英才和张国振

最近这几天逐渐完成了不少事情。俱乐部四场技术沙龙、三场培训讲座总算搞完&#xff0c;俱乐部活动也告一段落&#xff0c;我到下学期也快退休了。不少陈年旧债的手尾也完成了。IBM比赛的事情也在进展中&#xff0c;虽然受到前面事情的影响&#xff0c;不是很如意。RFID项目进入…