Go_面向对象
GO语言中没有class的定义, 但是struct实现了class的功能(方法, 继承等)
struct声明
type 标识符 struct{ field1 type field2 type } //例子 type Student struct{ Name string Age int Score int } // 新名字, 定义了一种新的类型, 其中字段与Student相同 type Stu Student type inter int
声明定义及访问
声明
var stu student var stu *Student = new(Student) // 返回指针 var stu *Student = &Student{字段:值,字段:值}// 返回指针
访问
// 通过.的方式去取值和设置值 func main() { var stu Student stu.Name = "自由" stu.Age = 18 stu.Score = 60 fmt.Println(stu) }
ps:
- 无论变量是指针类型还是非指针类型都可以直接使用.的方式去操作
- 结构体在内存中的布局是连续的, 是指类型, 函数传递要传递指针
- struct没有构造函数, 一般可以使用工厂模式来解决
func NewStudent(name string, age int) *Student{ return &student{ Name:name, Age: age } }
Tag : 我们可以为struct中的每个字段, 写上一个tag.这个tag可以通过反射机制获取到
type Student struct{ Name string "this is name field" Age int "this is age field" }
方法
go中的方法作用域特定类型的变量上, 因此自定义类型都可以有方法, 而不仅仅是struct
定义
func (object type) methodname (args) ( rets ){ // 方法体 }
示例
type Student struct{ Name string Age int Score int sex int } func (p Student) init(name string, age int, score int){ p.Name = name p.Age = age p.Score = score } func main(){ var stu Student stu.init("stu", 18, 100) }
不过上面的例子中并不会对stu产生影响, 因为p是stu的备份, 我们可以修改方法,使其接收指针
func (p *Student) init(name string, age int, score int){ (*p).Name = name (*p).Age = age (*p).Score = score } func main(){ var stu Student stu.init("stu", 18, 100) }
向上面这种不断的取值很麻烦, 好在go帮我们解决了此事, 当传入的是个指针时我们可以直接通过.的方式去去柱子
func (p *Student) init(name string, age int, score int){ p.Name = name p.Age = age p.Score = score } // 可以改变调用者的值
继承
结构体中的匿名字段, 变量可以直接去访问匿名变量的字段
type Animal struct{ Name string Age int } type Dog struct{ Animal Colour string } func main(){ var dog Dog dog.Name = "旺财" dog.Age = 2 dog.Colour = "斑点" fmt.Println(dog.Name, dog.Age, dog.Colour) }
名称冲突
当结构体中的字段与其内部匿名字段中的字段同名时, 默认访问的是自己的
当两个匿名字段中的字段相同时
type Sitiaotui struct{ Name string } type Dog struct{ Animal Sitiaotui Colour string } func main(){ var dog Dog dog.Animal.Name = "旺财" dog.Age = 2 dog.Colour = "斑点" fmt.Println(dog.Animal.Name, dog.Age, dog.Colour) }
方法的继承同字段相同
访问控制
属性及方法的首字母, 同包
接口
接口也是一种类型, 接口的应用相当的灵活.
接口规定了了实现了他的类必须定义的方法, 而在Go中不需要声明实现接口, 只要实现了该接口中的方法就可以认为实现了该接口.
接口定义
Interface类型可以定义一组方法, 但是这些不需要实现. 并且interface不能包含任何变量
type Test interface{ function(args)(rets) }
实现
结构体有指定方法就实现了该接口, 接口变量是个指针类型
一个类型实现了一个接口, 这个类型就可以给这个接口赋值
package main import "fmt" type Student struct{ Name string Age int Score int sex int } type Test interface { print() } func (p Student) print(){ fmt.Println(p) } func main(){ var t Test var stu Student = Student{ Name :"lihua", Age : 18} t = stu // 可以赋值给接口类型 t.print() }
接口的嵌套
type Writer interface{ Write() } type Reader interface{ Read() } type ReadWrite interface{ Reader Writer } func Test(rw ReadWriter){ rw.Read() rw.Write() }
空接口 interface{}: 任何类型都可以赋值给空接口类型的变量
String()方法 : Print调用的方法
package main import "fmt" type Student struct{ Name string Age int Score int sex int } func (p Student) String() string { return fmt.Sprintf("%s,%d, %d",p.Name, p.Age, p.sex) } func main(){ var stu Student = Student{ Name :"lihua", Age : 18} fmt.Println(stu) // lihua,18, 0 }
类型断言
将一个接口变量转换成类型
当确定类型时:
func main(){ var a interface{} var b int a = b c := a.(int) // 转回其他类型 fmt.Printf("%d %T", c,c) }
当不确定类型时, 带有错误信息
func main(){ s := 100 if v, ok := interface{}(s).(string); ok { fmt.Println(v) }else{ fmt.Println("不能转") } }
上面这种也可以判断是否实现了某个接口
type Test interface { print() } func (p Student) print(){ fmt.Println(p) } func main(){ var stu Student = Student{ Name :"lihua", Age : 18} t, ok := interface{}(stu).(Test) fmt.Println(t, ok, stu) }
返回具体类型
package main import ( "fmt" ) type Element interface {} func main() { var e Element = 100 switch value := e.(type) { case int: fmt.Println("int", value) case string: fmt.Println("string", value) default: fmt.Println("unknown", value) } }