结构体
Go 语言中没有“类”的概念,也不支持像继承这种面向对象的概念。但是Go 语言的结构体与“类”都是复合结构体,而且Go 语言中结构体的组合方式比面向对象具有更高的扩展性和灵活性。
结构体定义
结构体中字段的类型可以是任何类型,包括函数类型,接口类型,甚至结构体类型本身。
type identifier struct {
field1 type1
field2 type2
...
}
//例
type Student struct {
Name string
Age int
}
在声明结构体时我们也可以不给字段指定名字,例如下面这样
type Person struct {
ID string
int
}
我们可以看到其中有一个int字段没有名字,这种我们称其为匿名字段。对于一个结构体来说,每一种数据类型只能有一个匿名字段。
操作结构体
创建结构体的实例,可以使用如下几种方法创建,仍然以上面的Student结构体为例。
s1 := new(Student) //第一种方式
s2 := Student{"james", 35} //第二种方式
s3 := &Student { //第三种方式
Name: "LeBron",
Age: 36,
}
标签
在go语言中结构体除了字段的名称和类型外还有一个可选的标签tag,标记的tag只有reflect包可以访问到,一般用于orm或者json的数据传递,下面这段代码演示了如何为结构体打标签。
type Student struct {
Name string `json:"name"`
Age int `json:"age"`
}
我们可以使用go自带的json包将声明的结构体变量转变为json字符串。
func ToJson(s *Student) (string, error) {
bytes, err := json.Marshal(s)
if err != nil {
return "", nil
}
return string(bytes), nil
}
如果我们没有给结构体打标签输出的json字符串如下所示
{"Name":"james","Age":35}
如果我们给结构体打过标签之后输出的json字符串如下所示
{"name":"james","age":35}
方法
方法定义
方法与函数类似,只不过在方法定义时会在func和方法名之间增加一个参数,如下所示:
func (r Receiver)func_name(){
// body
}
其中r被称为方法的接收者,例如我们下面这个例子:
type Person struct {
name string
}
func (p Person) GetName() string {
return p.name
}
其中GetName方法的接收者为p是Person结构体类型,也就是说我们为结构体Person绑定了一个GetName方法,我们可以使用如下的方式进行调用。
func main() {
p := Person{
name:"james",
}
fmt.Println(p.GetName())
}
接口
接口定义
接口相当于一种规范,它需要做的是谁想要实现我这个接口要做哪些内容,而不是怎么做。在go语言中接口的定义如下所示:
type Namer interface {
Method1(param_list) return_type
Method2(param_list) return_type
...
}
实现接口
在go语言中不需要显示的去实现接口,只要一个类型实现了该接口中定义的所有方法就是默认实现了该接口,而且允许多个类型都实现该接口,也允许一个类型实现多个接口。
案例如下:
type Animal interface {
Eat()
}
type Bird struct {
Name string
}
func (b Bird) Eat() {
fmt.Println(b.Name + "吃虫")
}
type Dog struct {
Name string
}
func (d Dog) Eat() {
fmt.Println(d.Name + "吃肉")
}
func EatWhat(a Animal) {
a.Eat()
}
func main() {
b := Bird{"Bird"}
d := Dog{"Dog"}
EatWhat(b)
EatWhat(d)
}
在EatWaht函数中是传递一个Animal接口类型,上面的Bird和Dog结构体都实现了Animal接口,所以都可以传递到函数中去来实现多态特性。
类型断言
有些时候方法传递进来的参数可能是一个接口类型,但是我们要继续判断是哪个具体的类型才能进行下一步操作,这时就用到了类型断言,下面我们通过一个例子来进行讲解:
func IsDog(a Animal) bool {
if v, ok := a.(Dog); ok {
fmt.Println(v)
return true
}
return false
}
上面的方法对传递进来的参数进行判断,判断其是否为Dog类型,如果是Dog类型的话就会将其进行转换为v,ok用来表示是否断言成功。
但是如果我们对于一个类型有好多种子类型要进行判断,这样写的话显然是有些复杂,可以使用如下这种方式:
func WhatType(a Animal) {
switch a.(type) {
case Dog:
fmt.Println("Dog")
case Bird:
fmt.Println("Bird")
default:
fmt.Println("error")
}
}
空接口
因为其内部没有定义任何方法所以空接口可以表示任何一个类型
var any interface{}
any = 1
fmt.Println(any)
any = "hello"
fmt.Println(any)
any = false
fmt.Println(any)