前言
Golang也支持面向对象编程(OOP),但是和传统的面向对象编程有区别,并不是纯粹的面向对象语言。所以我们说Golang支持面向对象编程特性是比较准确的。
Golang没有类(class),Go语言的结构体(struct)和其它编程语言的类(class)有同等的地位,你可以理解Gelang是基于struct来实现OOP特性的。
Golang面向对象编程非常简洁,去掉了传统OOP语言的方法重载、构造函数和析构函数、隐藏的this指针等等。
Golang仍然有面向对象编程的继承,封装和多态的特性,只是实现的方式和其它OOP语言不一样,比如继承:Golang没有extends 关键字,继承是通过匿名字段来实现。
一、结构体
定义结构体的格式
type 结构体名 struct {
//结构体成员列表
成员名 数据类型
}
定义结构体的实例、对象、变量,属于复合类型
var 变量名 结构体名
定义结构体时为成员赋值(按顺序写)
var 变量名 结构体名 = 结构体名{ 按顺序写 成员变量值1,成员变量值2,… }
代码展示:
package main
import "fmt"
//结构体是一种数据类型
type Student struct {
id int
name string
sex string
age int
addr string
}
func main() {
var stu Student
// 为结构体成员赋值 可以不按顺序
stu.name = "张三"
stu.addr = "广东省xxxxxxxxx"
stu.age = 18
stu.sex = "男"
stu.id = 0
fmt.Println(stu) //{0 张三 男 18 广东省xxxxxxxxx}按照结构体的顺序打印
var stu2 Student = Student{1, "小丽", "女", 20, "广东xxxxxx"}
fmt.Println(stu2) //{1 小丽 女 20 广东xxxxxx}
}
如果是未赋值时,成员类型是默认值
func main() {
var stu Student
fmt.Println(stu)
}
结果:{0 0 }
定义结构体时为成员赋值(不按顺序写)
var 变量名 结构体名 = 结构体名{ 成员变量 : 值1 , 成员变量 : 值2 , …}
var stu2 Student = Student{name: "小丽", id: 1, sex: "女", addr: "广东xxxxxx", age: 20}
用自动类型推导
- 按顺序
stu2 := Student{2, "小丽", "女", 20, "广东xxxxxx"}
- 不按顺序,指定成员赋值,一般没人使用
stu2 := Student{name: "小丽",id: 1, sex: "女", addr: "广东xxxxxx", age: 20}
结构体是全局的,可以在项目中所有文件使用,不关大小写首字母。
既然stu2是变量,那么就符合我们所有变量操作的习惯,结构体占的内存大小=所有成员的大小的和。
结构体变量名本身不是地址,他是一个变量
package main
import "fmt"
//结构体是一种数据类型
type student struct {
id int
name string
sex string
age int
addr string
}
func main() {
stu := student{2, "小丽", "女", 20, "广东xxxxxx"}
fmt.Printf("%p\n", &stu) //0xc000020080
fmt.Printf("%p\n", &stu.id) //0xc000020080
//成员为string类型需要和结构体最大的数据类型进行对齐
fmt.Printf("%p\n", &stu.name)
//0xc000020088跟id差一个整形大小(int类型占8个大小)我的是Windows64
//int类型占8个大小,所以string类型起始位置和结束位置一定是8的倍数
fmt.Printf("%p\n", &stu.sex) //0xc000020098跟name差16个字节大小
}
结构体的赋值
package main
import "fmt"
//结构体是一种数据类型
type student struct {
id int
name string
sex string
age int
addr string
}
func main() {
stu := student{2, "小丽", "女", 21, "广东xxxxxx"}
//将结构体变量进行赋值操作
stu2 := stu
//两个地址不一样
fmt.Printf("地址:%p;%v\n", &stu, stu) // 0xc000020080 {2 小丽 女 21 广东xxxxxx}
fmt.Printf("地址:%p;%v\n", &stu2, stu2) // 0xc0000200c0 {2 小丽 女 21 广东xxxxxx}
stu2.id = 666
fmt.Println(stu) //{2 小丽 女 21 广东xxxxxx}
fmt.Println(stu2) //{666 小丽 女 21 广东xxxxxx}
}
结构体的比较
两个结构体比较是比较所有成员,如果成员相同,那么结果为真。
支持 == 或 != 比较操作,但不支持 > < <= 等等。
结构体1.成员和结构体2.成员只要类型相同可以进行比较。
package main
import "fmt"
//结构体是一种数据类型
type student struct {
id int
name string
sex string
age int
addr string
}
func main() {
stu := student{2, "小丽", "女", 21, "广东xxxxxx"}
stu2 := stu
if stu == stu2 {
fmt.Println("相同")//打印相同
} else {
fmt.Println("不相同")
}
}
如果成员有修改,打印不相同。我们修改上面代码的main
func main() {
stu := student{2, "小丽", "女", 21, "广东xxxxxx"}
stu2 := stu
stu2.id = 666
if stu == stu2 {
fmt.Println("相同")
} else {
fmt.Println("不相同") //打印不相同
}
}
二、结构体数组和切片
package main
import "fmt"
type Student struct {
id int
name string
age int
sex string
score int
addr string
}
func main() {
// 定义结构体数组
var arr [3]Student = [3]Student{
Student{0, "曹操", 25, "男", 80, "曹魏"},
Student{10, "小乔", 19, "女", 55, "东吴"},
Student{16, "大乔", 21, "女", 66, "吴"}}
//fmt.Println(arr)
/* 打印结构体信息 */
//for i := 0; i < len(arr); i++ {
// fmt.Println(arr[i])
//}
/* 修改指定结构体成员的信息 */
arr[1].score = 100
arr[2].score = 11
fmt.Println(arr)
}
结构体数组值传递
package main
import "fmt"
type Student struct {
id int
name string
age int
sex string
score int
addr string
}
func main() {
// 定义结构体数组
var arr [3]Student = [3]Student{
Student{0, "曹操", 25, "男", 80, "曹魏"},
Student{10, "小乔", 19, "女", 55, "东吴"},
Student{16, "大乔", 21, "女", 66, "吴"}}
BubbleSort(arr)
fmt.Println("main的arr:", arr) //没有排序
}
func BubbleSort(arr [3]Student) {
for i := 0; i < len(arr)-1; i++ {
for j := 0; j < len(arr)-1-i; j++ {
// 比较结构体成员的信息
if arr[j].age > arr[j+1].age {
//交换数组元素
arr[j], arr[j+1] = arr[j+1], arr[j]
}
}
}
fmt.Println(arr)
//[{10 小乔 19 女 55 东吴} {16 大乔 21 女 66 吴} {0 曹操 25 男 80 曹魏}]
}
结构体切片引用传递(地址传递)
package main
import "fmt"
type Student struct {
id int
name string
age int
sex string
score int
addr string
}
func main() {
// 定义结构体切片
var arr []Student = []Student{
Student{0, "曹操", 25, "男", 80, "曹魏"},
Student{10, "小乔", 19, "女", 55, "东吴"},
Student{16, "大乔", 21, "女", 66, "吴"}}
BubbleSort(arr)
fmt.Println("main的arr:", arr) //排序了
arr=append(arr,Student{12, "孙策", 22, "男", 99, "江东"})
fmt.Println(arr)
// [{10 小乔 19 女 55 东吴} {16 大乔 21 女 66 吴} {0 曹操 25 男 80 曹魏} {12 孙策 22 男 99 江东}]
}
func BubbleSort(arr []Student) {
for i := 0; i < len(arr)-1; i++ {
for j := 0; j < len(arr)-1-i; j++ {
// 比较结构体成员的信息
if arr[j].age > arr[j+1].age {
//交换数组元素
arr[j], arr[j+1] = arr[j+1], arr[j]
}
}
}
fmt.Println(arr)
//[{10 小乔 19 女 55 东吴} {16 大乔 21 女 66 吴} {0 曹操 25 男 80 曹魏}]
}
结构体实例创建:返回的是结构体指针
(1)
package main
import "fmt"
type Student struct {
id int
name string
sex string
age int
addr string
}
func main() {
var s *Student = new(Student)
//s是指针,s其实指向的就是地址,应该给这个地址的指向的对象的字段赋值:
(*s).name = "小乔"
(*s).age = 19 //*的作用:根据地址取值
s.addr = "东吴" //go编译器底层对s.addr转化(*s).addr="东吴"
fmt.Println(*s) //{0 小乔 19 东吴}
}
(2)
func main() {
var s *Student = &Student{10, "小乔", "女", 55, "东吴"}
fmt.Println(*s) //{10 小乔 女 55 东吴}
}
三、结构体之间的转换
(1)结构体是用户单独定义的类型,和其它类型进行转换时需要有完全相同的字段(名字、个数和类型)。
package main
import "fmt"
type Student struct {
Age int
}
type Person struct {
Age int
}
func main(){
var s Student = Student{10}
var p Person = Person{10}
s = Student(p)
fmt.Println(s)
fmt.Println(p)
}
(2)结构体进行type重新定义(相当于取别名),Golang认为是新的数据类型,但是相互间可以强转。
package main
import "fmt"
type Student struct {
Age int
}
type Stu Student
func main(){
var s1 Student = Student{19}
var s2 Stu = Stu{19}
s1 = Student(s2)
fmt.Println(s1)
fmt.Println(s2)
}
三、接口
Go 语言提供了另外一种数据类型即接口,它把所有的共性方法定义在一起,任何其它类型只要实现了这些方法就是实现了这个接口。
type 接口 interface{
方法1()
方法2(形参列表)(返回值类型)
…
}
type 结构体 struct{
}
/* 实现接口方法 /
func (结构体名 结构体) 接口方法1() {
/ 方法实现 */
}
func (结构体名 结构体) 接口方法2(形参列表)(返回值类型) {
}
①var car1 myCar = myCar{11}
package main
import "fmt"
// 定义一个接口,并且在接口中定义了抽象的方法
type InterCar interface {
//只需要定义方法,不需要实现
beep()
driver(driver string)(string,int)
}
//定义一个结构体
type myCar struct {
//默认只有属性没有方法
id int
}
//实现接口方法
func (car myCar) deep() {
//方法实现
fmt.Printf("car的id:%v\n",car.id)
}
func (car myCar) driver(driver string)(string,int){
fmt.Println(driver,",",car.id)
return driver,car.id
}
func main(){
var car1 myCar
car1 = myCar{11}
car1.deep()
car1.driver("hello")
}
②car1 := new(myCar)
car1.id = 10
修改main那行代码自己尝试