go语言学习第四天==》结构体、引用、匿名组合、接口、any类型
- 类型
基础类型,如byte int bool float等
复合类型 如数组,结构体,指针
可以指向任意对象的类型(any类型)
值语义和引用语义
面向对象,即所有具备面向对象特征(比如成员方法)的类型
接口
为类型添加方法
Go中,可以给任意类型(包括内置类型,但是不包括指针类型)
添加相应的方法
type Integer int
func (a Integer) Less(b Integer) bool {
return a < b
}
//使用
var a Interger=1
b:=a.less(2)
可以传入指针
func (a *Integer) Add(b Integer) {
*a += b
}
func main() {
var a Integer = 1
a.Add(2)
fmt.Println("a =", a)
}
//结果为3
如果不传指针
func (a Integer) Add(b Integer) {
a += b
}
//结果为1
引用
//非引用↓
var a = [3]int{1, 2, 3}
var b = a
b[1]++
fmt.Println(a, b)
//结果[123],[133]
/引用
var a = [3]int{1, 2, 3}
var b = &a
b[1]++
fmt.Println(a, *b)
//结果[133],[133]
结构体
demo
//定义结构体
type Rect struct {
x, y float64
width, height float64
}
//定义一个成员方法计算面积
func (r *Rect) Area() float64 {
return r.width * r.height
}
//在Go语言中,未进行显式初始化的变量都会被初始化为该类型的零值,
//如bool零值false,int零值为0,string零值为空字符串。
//所以创建实列对象可以这样:
rect1 := new(Rect)
rect2 := &Rect{}
rect3 := &Rect{0, 0, 100, 200}
rect4 := &Rect{width: 100, height: 200}
///
匿名组合
go也提供继承,但是采用组合的文法,称为匿名组合
type Base struct {
Name string
}
//再给它两个成员方法
func (base *Base) Foo() { ... }
func (base *Base) Bar() { ... }
这样来“继承”Base
type Foo struct {
Base ...
}
func (foo *Foo) Bar() {
foo.Base.Bar() ...
}
还可以以指针方式派生
type Foo struct {
*Base ...
}
//
可见性
要使某个符号对其他包可见,需将该符号定义为大写字母开头如
type Rect struct {
X, Y float64
Width, Height float64
}
如小写,就只能在该类型所在的包内使用
如以下成员方法
func (r *Rect) area() float64 {
return r.Width * r.Height
}
- 接口
接口在go中非常重要
///
非侵入式接口
注意:
go中结构体只要有该接口的所有要求函数,
则这个结构体就实现了该接口
demo
//定义File结构体
type File struct {
// ...
}
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 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
}
//File结构体并没有从这些接口继承,甚至不知道这些接口的存在,
//但是都实现了这些接口
//所以可以赋值
var file1 IFile = new(File)
var file2 IReader = new(File)
var file3 IWriter = new(File)
var file4 ICloser = new(File)
///
接口赋值
将对象实列赋值给接口
//有一个类型
type Integer int
func (a Integer) Less(b Integer) bool {
return a < b
}
func (a *Integer) Add(b Integer) { //有指针
*a += b
}
//接口
type LessAdder interface {
Less(b Integer) bool
Add(b Integer) //无指针
}
把Interger对象实列赋值给LessAdder接口
var a Integer = 1
var b LessAdder = &a //关键 A
/*
由于 A行
go语言根据下面的函数
func (a Integer) Less(b Integer) bool
自动生成
func (a *Integer) Less(b Integer) bool {
return (*a).Less(b)
}
这样类型*Interger就既存在less()方法,又存在add()方法 符合接口LessAdder
但是 无法 根据func (a *Integer) Add(b Integer)
自动生成
func (a Integer) Add(b Integer) {
(&a).Add(b) //关键行B
}
因为(&a).Add()改变的只是函数参数a,对外部实际要操作的对象并无影响,这不符合用 户的预期。
*/
//
将接口赋值给另一种接口
只要接口A的方法列表示接口B的方法列表子集,B就可以赋值给A,
方法列表相同可以相互赋值(列表顺序可以不同)
接口查询
demo
如果file1指向的对象实列实现了two.IStream接口,则ok=true
var file1 Writer = ...
if file5, ok := file1.(two.IStream); ok {
...
}
///
类型查询
变量名.(type)
如
v1:="im a boss"
v := v1.(type)
//fmt.Println(v) 结果为string
///
接口组合
把方法组合起来
如
// ReadWriter接口将基本的Read和Write方法组合起来
type ReadWriter interface {
Read(p []byte) (n int, err error)
Write(p []byte) (n int, err error)
}
/
any类型
go语言中任何对象实列都满足空接口interface[] 所以
var v1 interface{} = 1 // 将int类型赋值给interface{}
var v2 interface{} = "abc" // 将string类型赋值给interface{}
var v3 interface{} = &v2 // 将*interface{}类型赋值给interface{}
var v4 interface{} = struct{ X int }{1}
var v5 interface{} = &struct{ X int }{1}
当函数可以接受任意的对象实例时,我们会将其声明为interface{}
func Printf(fmt string, args ...interface{})
func Println(args ...interface{})