Go不是纯粹的面向对象语言,和传统的面向对象编程有区别,所以说Go语言支持面向对象编程特性是比较准确的。
Go语言基于结构体struct来实现OOP特性,通过type和struct关键字声明结构体,格式如下:
type 类型名 struct { // 类型名在同一个包内不能重复 字段1 字段1类型 // 字段名必须唯一 字段2 字段2类型 }
结构体从本质上讲是一种自定义的数据类型,只不过这种数据类型比较复杂,可以认为结构体是一种聚合类型。
声明结构体变量再赋值:
type Student struct { sid int // 字段首字母小写,类似private,其它包不能使用 course []string // 选修课程 } func main() { // 声明一个结构体对象,值类型,默认开辟空间,字段赋予零值 var s Student fmt.Println("s:", s) // s: {0 []} // 访问结构体成员使用点号 . 操作符 fmt.Println(s.sid) // 0 // 更改成员变量值 s.sid = 1001 fmt.Println(s.sid) // 1001 // 方式2:键值对赋值 s2 := Student{sid: 1002, course: []string{"chinese", "math"}} fmt.Println(s2) // 方式3:多值赋值 s3 := Student{1003, []string{"chinese", "math"}} fmt.Println(s3) }
实例化之&结构体:
func initSid(s *Student) { s.sid = 1001 // 其实是(*s).sid = 1001 } func main() { s := Student{course: []string{"chinese", "math"}} initSid(&s) fmt.Println(s) // {1001 [chinese math]} s2 := &Student{course: []string{"chinese", "math"}} initSid(s2) fmt.Println(s2) // &{1001 [chinese math]} }
实例化之new(结构体):
func main() { s := new(Student) // 等同于 &Student{} fmt.Println(s) // &{0 []} }
Go语言没有构造函数,但可以使用结构体初始化过程来模拟实现构造函数(首字母大写)。
// 自定义工厂函数,返回局部变量地址 func NewStudent(sid int, course []string) *Student { return &Student{ sid: sid, course: course} } func main() { s := NewStudent(1001, []string{"math", "english"}) fmt.Println(s) // &{1001 [math english]} }
Go语言中的方法(Method)是一种作用于特定类型变量的函数,这种特定类型变量叫做接收者(Receiver)。方法与函数的区别是,函数不属于任何类型,方法属于特定类型。
func (s Student) learn() { fmt.Printf("%d 正在学习...", s.sid) } func main() { s := NewStudent(1001, []string{"math", "english"}) s.learn() }
接收者是指针类型:
type Player struct { Name string HealthPoint int } func NewPlayer(name string, hp int) *Player { return &Player{ name, hp, } } func (p *Player) attack() { fmt.Printf("%s 发起攻击!\n", p.Name) } func (p *Player) attacked() { fmt.Printf("%s 被攻击!\n", p.Name) p.HealthPoint -= 10 fmt.Println("HealthPoint:", p.HealthPoint) } func main() { player := NewPlayer("张三", 100) player.attack() player.attacked() }
结构体允许其成员字段在声明时没有字段名而只有类型,这种没有名字的字段称为匿名字段。
type Person struct { string // 其实是string string int // 其实是int int } func main() { p := Person{ "张三", 18, } fmt.Println(p.string, p.int) // 张三 18 }
结构体也可以作为匿名字段使用:
type Addr struct { province string city string } type Person struct { string int Addr // 其实是Addr Addr } func main() { p := Person{ "张三", 18, Addr{"广东", "深圳"}, } fmt.Println(p.Addr.province, p.city) // 广东 深圳 }
当结构体中有和匿名字段相同字段时,采用外层优先访问原则。
每个目录一个包,main包包含可执行入口。
为结构定义的方法必须放在同一个包内,可以是不同文件。
// Animal 动物 type Animal struct { name string } func (a *Animal) eat() { fmt.Printf("%s is eating!\n", a.name) } // Dog 类型 type Dog struct { Kind string *Animal // 通过嵌套匿名结构体实现继承,直接写类型,没有字段名 } func (d *Dog) bark() { fmt.Printf("%s is barking ~\n", d.name) } func main() { d := &Dog{ Kind: "金毛", Animal: &Animal{ // 注意嵌套的是结构体指针 name: "旺财", }, } d.eat() d.bark() }
type Stu struct { Name string json:"name" // 结构体标签 Age int json:"-" // 表示不参与序列化 } func main() { stuStruct := Stu{Name: "张三", Age: 18} // 序列化 jsonStuStruct, _ := json.Marshal(stuStruct) fmt.Println(string(jsonStuStruct)) // {"name":"张三"} // 反序列化 var StuStruct Stu err := json.Unmarshal(jsonStuStruct, &StuStruct) if err != nil { return } fmt.Println(StuStruct) // {张三 0} }
本文作者:a
本文链接:
版权声明:本博客所有文章除特别声明外,均采用 BY-NC-SA 许可协议。转载请注明出处!