GO 面向对象


前言

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}

用自动类型推导

  1. 按顺序
stu2 := Student{2, "小丽", "女", 20, "广东xxxxxx"}
  1. 不按顺序,指定成员赋值,一般没人使用
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那行代码自己尝试

  • 3
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值