第四章 Go语言面向对象编程

一:为类型添加方法   Go这你可以为任何类型添加方法(不包括指针类型) 例如
type Integer int
 
func (a Integer) less(b Integer) bool {
return a < b
}
func main() {
var a Integer =3
if a.less(2) {
fmt.Println("返回的值a大于b")
}else {
fmt.Println("返回值 a小于b")
}
}
 
只有你必须改变对象的时候才要用指针类型  如下:
 
//a 是指针类型传递,这个可以改变a的值
func (a *Integer) Add(b Integer) {
*a+=b
}
 
//a是非指针类型传递 这个不可以改变a的值
func (a Integer) Addd(b Integer) {
a+=b
}
 
调用方式
var t Integer =3
t.Add(6)
fmt.Println("面向对象给类添加方法:",t)
 
t.Addd(8)
fmt.Println("面向对象给类添加方法这个传递的不是指针:",t)
输出的值
面向对象给类添加方法: 9
面向对象给类添加方法这个传递的不是指针:9
 
在Go中数组被定义为彻底的值类型,所以要改变数组值就要做指针传递 ,例如
 
//这个是一般的复制
var h =[3]int{1,2,3}
var b = h
b[1]++
fmt.Println("输出h的值:",h,"输出b的值:",b)
//这个是指针传递
var c =&h
c[1]++
fmt.Println("指针传递输出h的值:",h,"输出b的值:",*c)
 
var c =&h这句表示复制的事 h的引用,所以c不是[3]int类型,而是指针*[3]int类型
二:四个特殊类型分析   1):数组切片,数组切片本质上一个区间,因为数组切片内部是指向数组的指针,所以可以改变数组切片的元素(这也是为什么数组不能动态添加元素,但是切片可以的原因),但是数组切片类型本身的赋值仍然是值类型
 
       2)map本质上是一个字典指针,
       3)channel和map类似也是一个指针,channel和map不设计成值类型是因为,完整赋值map和chanel不是常规需求
4 )接口,接口是一个引用类型,内部维护了两个指针
 
 
以前我们说过,所有的Go语言类型(除了指针类型)都可以有自己的方法,在这个背景下,GO语言的结构体只是一个很普通符合类型, 比如:
 
type myup struct {
x, y int
w,h int
}
 
func (myu *myup) area() int {
return myu.x*myu.y
}
三:初始化    在定义了myup类型后,该如何创建并初始化myup类型,如下
                    
type myup struct {
    x, y int
    w,h int
}
 
这样来创建使用
myq :=new(myup)
myq2 :=&myup{}
myq3 :=&myup{1,2,3,4}
myq4 :=&myup{x:100,w:22}
 
在Go语言中为显示初始化的变量,都会被初始化为该类型的零值,例如 bool的零值是 false,int的零值是0 string的零值是空字符串
 
在Go 语言中没有构造函数的概念,对象的创建通常交给一个全局的创建函数完成,以Newxxx来命名,表示构造函数  如:
 
func Newmyup(x,y,w,h int) *myup {
   return &myup{x,y,w,h,}
}
 
 
四:匿名组合   准确的说Go语言也提供了继承,但是采用的是组合的方法,所以我们称为匿名组合
 
type Base struct {
Name string
}
 
func (base *Base) Foo() {
 
}
 
func (base *Base) Bar() {
 
}
 
type Foo struct {
Base
}
 
func (foo *Foo) Bar() {
foo.Base.Bar()
}
例如上面,定义了一个 Base基础类型,然后实现了Foo,Bar两个方法,然后定义了一个 Foo类,该类从Base类继承,并改写了Bar方法(该方法实现时先调用了积累的Bar方法),这样Go语言就清晰的告诉我们类的内存布局是怎么的啦,
 
另外 在Go语言中还可以以指针的方式从一个类型继承(派生)
type MyFoo struct {
*Base
}  这样在创建MyFoo实例的时候需要外部提供一个Base类型的指针
 
func mmy() {
   myfoo :=&Base{}
    myfoo.Base.Bar()
}
 
另外需要注意的就是 组合类型命名冲突的问题 如:
type myj struct {
Name string
}
type Myk struct {
myj
Name string
}
 
func (myo *Myk) Add {
fmt.Println(myo.Name)
fmt.Println(myo.myj.Name)
}
          其实这样是不会冲突的,所有的Myk类型Name成员访问的事最外成的那个Name变量,myj.Name相当于被隐藏了起来,
  
 
但是这样的就会报错 
 
type Logger struct {
Level int
}
type Y struct {
*Logger
Name string
*log.Logger
}
因为匿名组合类型相当于以其类型名称(去掉包名)作为成员变量的名称,所以Y里面相当于有两个 Logger成员
 
还需要注意一点,Go语言中成员的可访问性是包一级别的,不是类型一级别的,就是在同一个包内,不同的类型也可以访问其他类型的成员
 
五:接口  接口在Go语言中有着至关重要的作用,可以说是Go语言的基石
在go中实现类的时候,只需要关心自己应该提供哪些方法,不用纠结接口的分拆
 
package main
 
import "fmt"
 
//接口测试
 
type File struct {
 
}
 
func (f *File) Read(buf int) (n int,err error) {
fmt.Println("添加读文件")
return 2,nil
}
 
func (f *File) Wrire(buf int) (n int,err error) {
fmt.Println("添加些文件")
return 3,nil
}
 
func (f *File) Seek(off int64,whence int) (pos int64,err error) {
fmt.Println("跳跃读取")
return 4,nil
}
 
func (f *File) Close() error {
fmt.Println("关闭文件")
return nil
}
 
type IFile interface {
Read(buf int) (n int, err error)
Wrire(buf int) (n int,err error)
Seek(off int64,whence int) (pos int64,err error)
Close() error
}
 
type IRead interface {
Read(buf int) (n int, err error)
}
type IWrire interface {
Wrire(buf int) (n int,err error)
}
 
type IClose interface {
Close() error
}
 
func main() {
//File 虽然没有继承上面那些接口,可以说 不知道那些接口的纯在,但是File类已经实现了这些接口,如下面 可以进行赋值
buyt := 3
var file1 IFile=new(File)
file1.Read(buyt)
var file2 IRead =new(File)
file2.Read(buyt)
}
 
输出:
添加读文件
           添加读文件
六:接口赋值
         Go中接口赋值分为两种情况  1):将对象实例赋值给接口  2):将一个接口赋值给另一个接口
 
1:将对象实例赋值给接口,要求给对象实现了接口要求的所有方法
 
type Integer int
 
func (a Integer) Less(b Integer) bool {
return a<b
}
func (a *Integer) Add(b Integer) {
*a+=b
}
 
type LessAdd interface {
Less(b Integer) bool
Add(b Integer)
}
 
var a Integer=1
var b LessAdd=&a
b.Add(3)
fmt.Println("对象实例赋值给接口 %d",b)
对象实例赋值给接口 %d 0xc0420620a0
 
七:接口赋值给接口
 
       
type ReadWriter interface {
Read(buf int) (n int, err error)
Write(buf int) (n int,err error)
}
 
type IStream interface {
Write(buf int) (n int,err error)
Read(buf int) (n int, err error)
}
 
func rwgo() {
//测试接口赋值接口
var file1 ReadWriter =new(File)
var file2 IStream=file1
var file3 ReadWriter=file2
fmt.Println("数据",file3)
}
 
接口赋值的两个接口必须是等价的, 如果a接口的方法列表是b接口方法列表的子集,那么b接口可以赋值给a接口 ,但是a接口不能赋值给b接口
 
八:接口查询   代码如下
          
type IStream interface {
Write(buf int) (n int,err error)
Read(buf int) (n int, err error)
}
 
type IWrite interface {
Write(buf int) (n int,err error)
}
 
func chaxunjiekou() {
//如上面的接口 IWrite,怎么转化为 IStream接口,(IWrite接口少了一个Read方法,)这就要用到我们的接口查询啦,接口查询是在运行期才能确定的
var file1 IWrire= ...
if file5,ok :=file1.(IStream);ok {
 
}
九:接口组合
  这种形式就是接口组合
type My1 interface {
Read(buf int) string
}
type My2 interface {
Write(buf string) int
}
type My interface {
My1
My2
}
       这种组合的方式相当于把 My1和My2里面的声明都放到了My里面和这种是一样的
type MyTest interface {
   Read(buf int) string
   Write(buf string) int
}  
这个和前面我们说的的 ,类的匿名组合有点相识
 
10:Any类型
       在Go中任何对象实例都满足空接口interface{},所以interface{}可以看做是任何对象的Any类型  如下
var v1 interface{}=1
var v2 interface{}="aa"
var v3 interface{}=&v2
var v4 interface{}= struct {
x int
}{1}
 
当对象可以接受任何类型的时候,我们会将其声明为interface{},比如我们的printxx库就是一个例子
func printf(fmt string, args ...interface{})
 
 
 
posted @ 2018-08-03 18:08  瀚海行舟  阅读(155)  评论(0编辑  收藏  举报