结构体/接口
一.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() }