一.struct(结构体)
go中的struct可以实现oop中的类、方法
1.创建
type S1 struct {
Name string //成员
Age int //成员
Interfaceer //interface
Structer // struct
}
2.声明
var s S1
var s *S1
s := new(S1)
3.初始化
s = S1{Name: "go", Age: 2} // 或者 S1{"go", 2}
s = &S1{Name: "go", Age: 2}
4.方法:
go语言中的oop很另类,类在go里面叫做receiver,receiver可以是除了interface之外的任何类型。方法和类并非组织在一起,传统的oop方法和类放在一个文件里面,而go语言只要在同一个包里就可,可分散在不同文件里。go的理念就是数据和实现分离.
定义:
func (recv receiver_type) methodName(parameter_list) (return_value_list) { … }
func (_ receiver_type) methodName(parameter_list) (return_value_list) { … }
func (this receiver_type) methodName(parameter_list) (return_value_list) { … }
func (self receiver_type) methodName(parameter_list) (return_value_list) { … }
reciever最好定义成指针的形式,因为方法中可能对成员有更改操作.
示例代码:
type S1 struct {
Name string
Age int
}
func (s1 *S1) ChangeName(name string) {
s1.Name = name
}
func main() {
s := &S1{Name: "go", Age: 2}
s.ChangeName("golang")
fmt.Println(s.Name)
}
5.相当另类的构造方法:
type S1 struct {
Name string
Age int
}
// 实现了一个构造方法
func NewS1(n string, a int) *S1 {
return &S1{n, a}
}
func main() {
s := NewS1("go", 1)
fmt.Println(s.Name)
}
6.匿名域(类似继承)
type Info struct {
From string
ResNum int
}
type S1 struct {
Name string
Age int
Info //这是一个匿名域
}
func main() {
s := new(S1)
s.From = "google" // From在struct唯一,所以可以直接访问
s.ResNum = 1000 // ResNum在struct唯一,所以可以直接访问
fmt.Println(s)
}
二.接口
Go语言中的接口是一些方法的集合(method set),它指定了对象的行为:如果它(任何数据类型)可以做这些事情,那么它就可以在这里使用.
Go语言中一个类只需要实现了接口要求的所有函数,我们就说这个类实现了该接口.
1.定义
type Namer interface {
Method1(param_list) return_type
Method2(param_list) return_type
}
2.接口赋值
(1).通过struct实例赋值
要求对象实现了接口的所有方法
type Selecter interface {
Read() int
}
type File struct {
file string
}
func (f *File) Read() int {
return len(f.file)
}
func main() {
file := File{file: "a.txt"} // 创建一个File实例
selecter := file // 将实例赋值给接口
fmt.Println(selecter.Read())
}
也可以这样:
file := new(File)
file.file = "a.txt"
selecter := file // 将一个指针赋值给接口
fmt.Println(selecter.Read())
// 也可以这样
file := Selecter(File)
(2).将接口赋值给另一个接口
假设接口A中定义的所有方法,都在接口B中有定义,那么B接口的实例可以赋值给A的对象。反之不成立.也就是B要包含A,就可以将B接口实例赋值给A
type Selecter interface {
Read() int
}
type Selecter2 interface {
Read() int
Write() int
}
type File struct {
file string
}
func (f *File) Read() int {
return len(f.file)
}
func (f *File) Write() int {
return len(f.file)
}
func main() {
var selecter2 Selecter2 = &File{file: "a.txt"}
var selecter Selecter = selecter2 //Selecter中的方法都在Selecter2中,所以可以将Selecter2的实例赋值给Selecter
fmt.Println(selecter.Read())
}
3.接口嵌套
type Selecter2 interface {
Selecter
Write() int
}
//等同于:
type Selecter2 interface {
Read() int
Write() int
}
4.空接口
空接口比较特殊,它不包含任何方法
在Go语言中,所有其它数据类型都实现了空接口。
t := []int{1, 2, 3, 4}
s := make([]interface{}, len(t)) //int也实现了空接口,所以可以用interface{}来代替
for i, v := range t {
s[i] = v
}
fmt.Println(s)
5.接口查询
检查对象是否实现了某个接口
type Reader interface {
Read() int
}
type Writer interface {
Write() int
}
type File struct {
filename string
}
func (f *File) Read() int {
return len(f.filename)
}
func main() {
var reader Reader = new(File)
if v, ok := reader.(Writer); ok { // 检查是否实现了Writer接口
fmt.Println(v, "reader 实现了Writer接口")
}
}
6.类型查询:
在Go语言中,我们可以使用type switch语句查询接口指向的对象实例的类型.一般是和接口查询配合使用.
import (
"fmt"
)
type Reader interface {
Read() int
}
type File struct {
filename string
}
func (f File) Read() int {
return len(f.filename)
}
func main() {
var reader Reader = File{filename: "a.txt"}
switch v := reader.(type) { // reader必须是一个接口类型
case File: // v类型是File
fmt.Println("File", v)
}
}
关于golang的结构体与接口:
结构体定义了属性,接口定义了方法.两者松耦合.举个例子:会英语要会读会写(要实现Read和Write两个方法的接口),如果一个学生(struct,包含学号,姓名等),实现了会读会写,那么就可以说这个学生会英语.如果一个老师(struct,包含学号,姓名等),实现了会读会写,我们就说这个老师会英语.
Duck Type:当看到一只鸟走起来像鸭子、游泳起来像鸭子、叫起来也像鸭子,那么这只鸟就可以被称为鸭子。
我们并不关心对象是什么类型,到底是不是鸭子,只关心行为.
7.类型断言
接口类型向普通类型的转换称为类型断言(运行期确定);
value, b := interface.(Type),value 是 Type 的默认实例;b 是 bool 类型,表明断言是否成立
func main() {
var arr []int
if b, ok := interface{}(arr).(int); ok { // arr赋值给空接口,判断是否是int类型
fmt.Println(b)
} else {
fmt.Println("not int array")
}
}
三.关于继承
1.属性继承
type Father struct {
Name string
}
type Son struct {
Father
age int
}
func main() {
son := Son{Father{"son"}, 10} // 初始化Father
fmt.Println(son.Father.Name)
}
2.方法继承(这个举例不是很妥当)
type Say interface {
SayName()
SayAag()
}
type Son struct {
name string
Say
}
func (this *Son) SayName() {
fmt.Println(this.name)
}
func main() {
son := new(Son)
son.name = "Son"
son.SayName()
}
3.多重继承
// Father
type Father struct {
Book string
}
func (this *Father) Say() {
fmt.Println("hello world")
}
func (this *Father) Read() {
fmt.Println(this.Book)
}
// Monther
type Monther struct {
Age int
}
func (this *Monther) Say() {
fmt.Println("hello world")
}
// 继承Father和Monther, 并添加一个属性
type Son struct {
xuehao int
Father
Monther
}
func main() {
son := new(Son)
son.xuehao = 150
son.Book = "<rolling>"
son.Age = 15
son.Read()
//son.Say() // 出错,因为Father和Monther都有Say方法,产生混淆
son.Father.Say()
}