Go摒弃了许多OO的概念,但是还是很好的继承了OO的精髓——消息传递。我猜这个是学了Smalltalk的。通常我们说OO,我们会说这三大特性:对象,继承,多态。
1,Go中的对象
对于GO来说他的类型系统也分为两类:value type和reference type。value type就是内存中的内容,reference其实也是类似引用地址的指针。这样Go中的对象很自然的分为两类的:内容和引用内容的地址。Go的一个哲学就是让“天下没有隐晦的东西”。所以Go的对象在内存中的表示和其定义是一一对应的。有点“what you see is what you get”的感觉。
而在Go中,实现对象特征的是struct,其实这个好理解。当年C++之父Bjarne Stroustrup在从C语言捣腾C++的时候也是先扩展C中的struct,只不过,Bjarne Stroustrup太贪心,做的太多的。这个在学术上是有意义的,但在工程上并不买账。
Go中一切直白,没有隐藏的this指针。struct定义决定了struct内存的布局。但是Go添加了method,其实就是附加在struct上的一系列方法。我们可以通过struct的变量(相当我们OO中的实例)来调用这些方法。这些其实就是写语法糖而已。让原本C中的:
sayHello(Person *p, char *msg);
变成了类似于:
p := new(Person)
p.sayHello(msg string)
即使这小小的一变,在意义上变化大着了。这里的p是variable,Go称这样的variable为receiver。其实就是OO中的消息传递,而这个接受者就是p这个变量。
Go中有一点小的改进,调用语法上取消了对struct的变量和变量指针的区别。在上例中p := new(Person)中的p其实是new返回的指向Person变量的一个指针。但是我们仍然可以用点号来调用:p,sayHello()。
Go中的对象就这些,没有别的了。
2,Go中的继承
C++中的继承是很隐晦的,子类的constructor会自动调用父类的constructor,等等,等等。我们所谓的继承,其实是为了一种共享。这个共享,是通过嵌入来实现的。传统的OO语言中把这个工作交给编译器了,通过一些语法支持,编译器会创建一个父类对象的实例,然后通过类似base的指针去引用父类对象。好处就是创建时相对会简单,在工程上的缺点就是如果你不了解这些语法规则,那么你写的代码中有很多的坑——最可怕的是你并值知道有这些坑。
Go仍然是本着“all things are obvious”,组合就是组合,即把一个类型嵌入到另一个类型中。看个例子:
package main import "fmt" type Cellphone struct {
brand string
name string
number string
cost float32
} func (c *Cellphone) showNumber() {
fmt.Println("number:" + c.number)
} type Person struct {
Cellphone
name string
age int
} func (p *Person)showPersonalInfo() {
fmt.Printf("name:%s\tage:%d\t", p.name, p.age)
p.showNumber();
} func main() {
p := Person{Cellphone{"moto", "Defy", "+86-13844448888", 2000}, "jerry", 31} p.showNumber() fmt.Println(p.brand) //output:moto fmt.Println(p.name) //output:jerry p.showPersonalInfo() }
直接将一个类型定义中引用需要嵌入的类型。Go做了一些语法上的支持:
1,可以直接调用嵌入类型的方法,比如p.showNumber()。或是直接引用嵌入类型的字段p.brand
2,可以嵌入多个类型。例子中没有显示。
3,每个类型只能嵌入一次。
4,当嵌入的类型和当前类型类型有重名的时候,当前类型覆盖(重写?)嵌入(父类?)类型的字段。这个模拟了子类overwrite父类父类的功能。比如例子中的p.name显示的是Person这个struct的name。
5,当嵌入的类型超过一个,并且有字段有重名的情况。这时候我们可以明确地引用比如p.Cellphone.name。否则编译时会有类似:xxx ambigous的错误。
Go的继承也就这么多了,他的想法就是,让显性(obvious)的东西保持显性。即使使用了语法糖,也绝不在后面做小动作。
3,Go中的多态
短答案:Go中没有多态。面向对象中的多态其本质是方法的分发。通过类似于virtual table的东西记录下分发的规则。有复写的时候方法分发给当前实例(子类)方法,没有复写的时候分发给父类相应的方法。Go中不允许不同类型的赋值,所以从根本上不支持传统OO中的多态。
Go中通过interface来实现(契约式)方法的分发。interface定义了方法的签名,任意类型只要实现了该方法,我们就认为这个类型实现了这个接口。这个不需要在定义类型的时候指定该类型所要实现的接口的方式被称之为“非入侵式的接口(non-invasive interface)”。
Go虽然不容许不同类型间的赋值,但是接口是个例外(接口在Go的内部也是一种特别的type)。只要一个类型实现了该接口,我们就可以将该类型的变量赋值给该接口的变量:
//Interfaces
type Shaper interface {
Area() float32
} //Square
type Square struct {
border float32
} //we can assign the variable of Square to variable of Shaper(interface)
var ishaper Shaper = &Square{20.0}
这样Shaper的变量就可以引用任意一个实现了该接口类型的变量了。在底层接口变量其实是一个带着两个数据的指针:一块数据是该receiver(即引用的实际变量),另一块是该接口实现的方法表指针。借助于这点Go多态也就完善了。Go中称这个位type assertion。其实也就是OO中的类型推断。我们可以通过类似这样的语法去看变量是否实现了接口,或者是从接口中得到具体的类型:
ishaper = s //assign a variable to interface variable
fmt.Println(ishaper.Area()) //tye assertion, get value from interface
if v, ok := ishaper.(*Square); ok {
fmt.Println(v)
} //type assertion to test value implement a interface
//type assertion is only applied on interface, so we cast the s to empty interface
if v, ok := interface{}(s).(Shaper); ok {
fmt.Println(v.Area())
}
好了,现在不难写出来体现多态的方法了,记住本质就是方法分发(method dispatch):
func PrintArea(s Shaper) {
fmt.Printf("The area is %v\n", s.Area())
}
如果你想实现可以接受任意参数的函数怎么办?Go中的空接口可以实现这个功能,空接口其实就是没有任何方法的接口:
type Any interface{ }
任何类型都实现了空接口,也就是说Any接口的变量可以引用任意一个其他类型的变量,在利用type assertion,我们可以写出通用的方法:
func PrintArea(s interface{}) {
if v, ok := s.(Shaper); ok {
fmt.Printf("The area is %v\n", v.Area())
}
}
完整示例:
package main import "fmt" //Interfaces
type Shaper interface {
Area() float32
} //Square
type Square struct {
border float32
} func (s *Square)Area() float32 {
return s.border * s.border
} //Rectangle
type Rectangle struct {
width float32
height float32
} func (r *Rectangle)Area() float32 {
return r.width * r.height
} //Polymorphism
func PrintArea(s interface{}) {
if v, ok := s.(Shaper); ok {
fmt.Printf("The area is %v\n", v.Area())
}
} func main() {
s := new(Square)
s.border = 2.0 var ishaper Shaper = s //assign a variable to interface variable
fmt.Println(ishaper.Area()) //tye assertion, get value from interface
if v, ok := ishaper.(*Square); ok {
fmt.Println(v)
} //type assertion to test value implement a interface
//type assertion is only applied on interface, so we cast the s to empty interface
if v, ok := interface{}(s).(Shaper); ok {
fmt.Println(v.Area())
} //Type switches
switch ishaper.(type) {
case *Square:
fmt.Println("Square type")
} r := &Rectangle{10.0, 15.0}
//a interface variable is a pointer in essence, so can pass the variable r(a pointer)
PrintArea(s)
PrintArea(r)
}
Go的多态也讲完了。
Go对OO的选择的更多相关文章
-
SAP ALV OO 选择行打印
&---------------------------------------------------------------------* *& Report ZSDF001 * ...
-
选择语句=》OO函数实现
let a; let b; if (a==="A") { b='定向' }else if (a==='B') { b='开放' }else if(a==='C') { b='全部' ...
-
如何选择PHP框架?
PHP是世界上最受欢迎的编程语言之—.最近发布的PHP7令这种服务器的编程语言比以前变得更好,更稳定了. PHP被广泛应用于重大的项目.例如Facebook就是使用PHP来维护和创建它们的内部系统的. ...
-
.net开发,html ajax开发架构之我见 bs ajax最简化法 Knock out Request,totally oo
.net开发中,无论ajax还是webform,webpage, 总免不了要和request这个静态全局,可以远程通信的对象打交道. 而对于软件来讲,按照Matin Fowler的的面向对象,可利用软 ...
-
ALV详解:OO SALV
声明:原创作品,转载时请注明文章来自SAP师太技术博客( 博/客/园www.cnblogs.com):www.cnblogs.com/jiangzhengjun,并以超链接形式标明文章原始出处,否则将 ...
-
ALV详解:OO ALV
声明:原创作品,转载时请注明文章来自SAP师太技术博客( 博/客/园www.cnblogs.com):www.cnblogs.com/jiangzhengjun,并以超链接形式标明文章原始出处,否则将 ...
-
ABAP OO的八大理由
原贴地址:http://scnblogs.techweb.com.cn/abaplv/archives/127.html 几年前SAP BASIS 4.6为ABAP扩展了OO功能,这是很多传统的ABA ...
-
OO ALV 学习参考
http://blog.csdn.net/sapliumeng/article/details/18653491 一.ALV介绍 The ALV Grid Control (ALV = SAPLi ...
-
OO真经——关于面向对象的哲学体系及科学体系的探讨(下)
真经第六章——运作 Moving “运动是绝对的——牛顿” 6.1.导言 在前五章中,我们从世界观的这话题开始,逐步引出了抽象.层次.继承和耦合.这些内容,形成了对象论中关于世界的结构体系. ...
随机推荐
-
(三)WebGIS前端地图显示之根据地理范围换算出瓦片行列号的原理(核心)
文章版权由作者李晓晖和博客园共有,若转载请于明显处标明出处:http://www.cnblogs.com/naaoveGIS/. 1.前言 在上一节中我们知道了屏幕上一像素等于实际中多少单位长度(米或 ...
-
第39课 Qt中的事件处理(下)
1. 事件的传递过程 (1)操作系统检测到用户动作时,会产生一条系统消息,该消息被发送到Qt应用程序 (2)Qt应用程序收到系统消息后,将其转化为一个对应的QEvent事件对象,并调用QObject: ...
-
MVC3在IIS7.5发布(部署)报403.14错误的解决办法
MVC3在IIS7.5发布(部署)报403.14错误的解决办法 错误现象: 报403.14 forbidden错误 web服务器被配置为不列出此目录的内容. 解决办法: 检查站点的处理程序映射 ...
-
SQLServer多表连接查询
双表内部连接查询 select wName,dName from DepartMent,Worker where DepartMent.dID=Worker.did select wName,dNam ...
-
11. Evaluate Reverse Polish Notation
Evaluate the value of an arithmetic expression in Reverse Polish Notation. Valid operators are +, -, ...
-
HTML5本地存储之localStorage、sessionStorage
1.概述 localStorage和sessionStorage统称为Web Storage,它使得网页可以在浏览器端储存数据. sessionStorage保存的数据用于浏览器的一次会话,当会话结束 ...
-
ONVIF Event消息解析(How to work with gSoap)
Prepare Requirements ONVIF Event gSoap reference ONVIF Specification 问题描述 Event是ONVIF核心规范中一块, 文档解释了如 ...
-
HDU 1039 -Easier Done Than Said?
水水的 #include <iostream> #include <cstring> using namespace std; ]; bool flag; int vol,v2 ...
-
wow.js中各种特效对应的类名
一.(页面在向下滚动的时候,有些元素会产生细小的动画效果.虽然动画比较小,但却能吸引你的注意.) 刚知道wow.js这个插件,之前访问别的网站下拉滚动条会出现各种效果感觉特别神奇,现在自己依葫芦画瓢也 ...
-
Django的设计模式
MVC模式 MVC将应用程序分解为三个组成部分:mode(模型).view(视图).control(控制器),其中: M 管理应用程序的状态(通常存储到数据库中),并榆树改变状态的行为(或者叫&quo ...