参考书:Go语言编程
1 Go语言中,你可以给任意类型(包括内置类型,但不包含指针类型)添加相应的方法,如下
type Integer int func (a Integer) Less(b Integer) bool{ // 给Integer类型定义成员函数 return a < b } func main(){ var a Integer = 1 if a.Less(2){ fmt.Println(a," less 2") } }
2 Go语言中没有隐藏的this指针,即方法施加的对象为显示传递,也不需要非得是指针,也不用非得叫this
3 数组作为参数传递为值传递,即函数内修改不会影响原数组,数组切片作为参数传递为引用传递,即函数内修改会影响原数组
4 如果需要修改对象,才必须使用指针,如下
type Integer int func (a *Integer) Add(b Integer){ *a += b } func (a Integer) Add2(b Integer){ a += b } func main(){ var a1 Integer = 1 a1.Add(2) fmt.Println("a = ",a1) // 输出 a = 3,因为Add()传入的是指针 a1.Add2(2) fmt.Println("a = ",a1) // 输出 a = 3,因为Add2()传入的是值,所以函数修改不影响对象 }
5 Go语言的类型哪些属于值传递
- 基础类型(如byte,int,bool,float32,float64和string等)和复合类型(如数组,结构体和指针等)属于值传递
- 数组切片,map和channel,接口这4种类型一般属于引用类型
注:
1)数组切片本质是指向数组的一个区间,内部是指向数组的指针
2)map本质也是一个字典指针
3)channel和map类型,本质上也是一个指针
4)接口具备引用语义,是因为内部维持了两个指针,示意为:
type interface struct {
data *void
itab *Itab
}
6 结构体,如下
type Rect struct { x , y float64 width,height float64 } func (r *Rect) Area() float64{ return r.width * r.height } rect1 := new(Rect) // 第一种初始化方式 rect2 := &Rect{} // 第二种初始化方式 rect3 := &Rect{0,0,100,200} // 第三种初始化方式 rect4 := &Rect{width:100,height:100} // 第四种初始化方式
7 匿名组合,用组合的方式来实现继承
type Base struct { Name string } func (base *Base) Foo(){ } func (base *Base) Bar(){ } type Foo struct { Base } func (foo *Foo) Bar(){ foo.Base.Bar() }
8 Go语言中没有关键字private,public和protected,可访问性是包一级而不是类一级。
9 Go语言采用非侵入式接口
type File struct {
// toDo. . .
}
func (f *File) Read(buf []byte) (n int , err error)
func (f *File) Write(buf []byte) (n int , err error)
func (f *File) Seek(off int64 , whence int) (pos int64 , err error)
func (f *File) Close( ) error
定义了一个File类,并实现有Read( ) , Write( ) , Seek( ) , Close( )等方法。设想我们有如下接口
type IFile interface {
Read(buf []byte) (n int , err error)
Write(buf []byte) (n int , err error)
Seek(off int64 , whence int) (pos int64 , err error)
Close( ) error
}
type IReader interface {
Read(buf []byte) (n int , err error)
}
type IWriter interface {
Write(buf []byte) (n int , err error)
}
type ICloser interface {
Close( ) error
}
var file1 IFile = new(File)
var file2 IReader = new(File)
var file3 IWriter = new(File)
var file4 ICloser = new(File)
10 将对象实例赋值给接口
type Integer int func (a Integer) Less(b Integer) bool{ return a < b } func (a *Integer) Add(b Integer){ *a += b } type LessAdder interface { Add(b Integer) Less(b Integer) bool } type LessAdder2 interface { Less(b Integer) bool } var a Integer = 1 var b LessAdder = a // error,因为LessAdder接口包含Add(),而类型a的Add()函数要改变对象值,需要地址赋值 var c LessAdder = &a // ok var d LessAdder2 = a // ok,因为LessAdder接口没包含Add(),不要求地址赋值 var e LessAdder2 = &a // ok
11 接口给接口赋值,如果两个接口同样的方法列表可以相互赋值,如果一个接口的方法列表是另一个接口的方法列表的子集。接口可以赋值给子集的那个,不能反了。
type File struct {
// toDo. . .
}
func (f *File) Read(buf []byte) (n int , err error)
func (f *File) Write(buf []byte) (n int , err error)
func (f *File) Seek(off int64 , whence int) (pos int64 , err error)
func (f *File) Close( ) error
type A interface {
Read(buf []byte) (n int , err error)
Write(buf []byte) (n int , err error)
}
type B interface {
Read(buf []byte) (n int , err error)
}
var file1 A = new(File)
var file2 B = file1 // 接口A可以给接口B赋值,接口B是接口A的子集
12 接口查询,如下
if file5 , ok := file1.(IReder) ; ok { // 检查file1接口指向的对象实例是否实现了IReader接口
// toDo
}
13 类型查询,采用 .(type) ,如下
var i int = 12
fmt.Println("i的类型为 ", i.(type)) // i的类型为int
14 Any类型:任何对象实例都满足空接口interface{ },如下
var v1 interface{ } = 1
var v2 interface{ } = "abc"
var v3 interface{ } = &v2
var v4 interface{ } = struct{ X int }{1}