Go语言学习(五)---指针、类型定义、结构体、方法、接口

目录

一、golang指针

1.1指针语法

1.2golang指针数组

二、golang类型定义和类型别名

2.1golang类型定义和类型别名的区别

三、结构体

3.1结构体的定义

匿名结构体

直接定义一个结构体类型的变量

3.2结构体的初始化

3.3结构体指针

3.4golang结构体作为函数参数

3.5golang中结构体的嵌套

四、golang方法

4.1语法

4.2 go语言方法的注意事项

​编辑4.3golang方法接收者类型

五、golang接口

5.1接口的语法格式

 5.2golang接口 值类型和指针类型

5.3 golang接口和类型的关系

一个类型实现多个接口

多个类型实现一个接口  

5.4 golang接口嵌套

5.5 golang通过接口实现OCP设计原则

5.6 golang中模拟OOP(面向对象)中的属性和方法

5.7golang继承

5.8 golang构造函数

一、golang指针

Go语言中的指针操作非常简单,只需要记住两个符号:&(取地址)、*(根据地址取值)

Go中的指针不能进行偏移和运算

1.1指针语法

一个指针变量指向了一个值的内存地址(也就是说我们声明了一个指针之后,可以像变量赋值一样,把一个值的内存地址放入到指针中)

var var_name *var_name

package main

import (
	"fmt"
)

func main() {
	var ip *int
	fmt.Printf("ip:%v\n", ip) //ip:<nil> 指针在没有赋值时是nil
	fmt.Printf("ip:%T\n", ip) //ip:*int

	//赋值
	var i int =100
	ip=&i
	fmt.Printf("ip:%v\n", ip) //ip:0xc00000a110 可以看到i内存地址
	fmt.Printf("ip:%v\n", *ip) //ip:100 可以看到ip指针中存放的内存地址对应的内容

	var sp *string
	var s string = "hello"
	sp=&s
	fmt.Printf("sp:%T\n", sp) //sp:*string
	fmt.Printf("sp:%v\n", sp) //sp:0xc000024070
	fmt.Printf("sp:%v\n", *sp) //sp:hello

}

1.2golang指针数组

定义语法 表示数组里面的元素的类型是指针类型

var ptr [MAX]*int

package main

import (
	"fmt"
)
/*
golang指向数组的指针
*/
func main() {
	a:=[3]int{1,2,3}
	var pa [3]*int
	fmt.Printf("pa:%v\n", pa) //pa:[<nil> <nil> <nil>]
	for i := 0; i < len(a); i++ {
		pa[i]=&a[i] //把a中每个元素的地址取出来赋值给pa
	}
	fmt.Printf("pa:%v\n", pa) //pa:[0xc00000e0f0 0xc00000e0f8 0xc00000e100]
	for i := 0; i < len(pa); i++ {
		fmt.Printf("pa:%v ", *pa[i]) //pa:1pa:2pa:3
	}
}

二、golang类型定义和类型别名

2.1golang类型定义和类型别名的区别

2.2类型定义

type NewType Type

2.3类型别名

type NewType = Type

 示例

package main

import (
	"fmt"
)
/*
golang类型定义和类型别名
*/
func main() {
	//类型定义
	type MyInt int
	var i MyInt
	i=100
	fmt.Printf("i:%T\n",i) //i:main.MyInt i的类型是MyINt不再是int
	fmt.Printf("i:%v\n",i) //i:100

	//类型别名
	type MyInt1 = int
	var j MyInt1
	j=100
	fmt.Printf("j:%T\n",j) //j:int
	fmt.Printf("j:%v\n",j) //100
}

三、结构体

3.1结构体的定义

package main

import (
	"fmt"
)
/*
golang结构体
*/
//定义
type Person struct{
	id int
	name string
	age int
}
func main() {
	//声明一个结构体变量
	var tom Person
	fmt.Printf("tom:%v\n", tom) //tom:{0  0} 没有初始化时,每个成员都是最初的值
	tom.id=10
	tom.age=20
	tom.name="tom"
	fmt.Printf("tom:%v\n", tom) //tom:{10 tom 20}
	// kite:=Person()
	// fmt.Printf("kite:%v\n", kite)
}

匿名结构体

直接定义一个结构体类型的变量

package main

import (
	"fmt"
)
/*
golang结构体
*/
//定义
// type Person struct{
// 	id int
// 	name string
// 	age int
// }
func main() {
	var dog struct{
		id int
		name string
	}
	dog.id=1
	dog.name="zxx"
}

3.2结构体的初始化

package main

import (
	"fmt"
)
/*
golang结构体初始化
*/
//定义
type Person struct{
	id int
	name string
	age int
}
func main() {
	var tom Person
	//方法一:使用键值的形式初始化 也可以部分初始化
	tom = Person{
		id:101,
		name:"tom",
		age:20,
	}
	fmt.Printf("%v", tom) //{101 tom 20}
	//方法二:通过顺序的方法初始化
	var amy Person
	amy = Person{
		102,
		"amy",
		19,
	}
	fmt.Printf("%v", amy) //{102 amy 19}
	//方法三:通过直接赋值的方式初始化
	var kite Person
	kite.id=103
	kite.name="kite"
	kite.age=21
	fmt.Printf("%v", kite)//{103 kite 21}
}

3.3结构体指针

package main

import (
	"fmt"
)
/*
golang结构体指针
*/
//定义
type Person struct{
	id int
	name string
	age int
}
func main() {
	var tom Person
	tom = Person{
		id:101,
		name:"tom",
		age:20,
	}
	var p_person *Person //定义一个结构体类型的指针,指针名称为p_person
	p_person=&tom
	fmt.Printf("%v", tom) //{101 tom 20}
	fmt.Printf("%v", p_person) //&{101 tom 20}
	fmt.Printf("%p", p_person) //0xc0000603a0  占位符是p表明输出指针类型,输出地址
	fmt.Printf("%v", *p_person) //{101 tom 20}

	//使用new创建一个结构体指针
	var amy=new(Person)
	fmt.Printf("%p", amy) //0xc000060440 指针类型
	(*amy).id=101 //理论上的写法,但是这里*可以忽略,就变成下面这种常见写法
	amy.age=23 
	amy.name="amy"
	fmt.Printf("%v", *amy) //{101 amy 23} 注意打印输出时要加星号
	
}

3.4golang结构体作为函数参数

package main

import (
	"fmt"
)
/*
golang结构体作为函数参数
*/
//定义
type Person struct{
	id int
	name string
}
//值传递,拷贝了一份副本
func showPerson(per Person){
	per.id=101
	per.name="amy"
	fmt.Printf("last:%v\n", per) 
}
func showPerson2(per *Person){
	per.id=102
	per.name="anna"
	fmt.Printf("last:%v\n", per) 
}
func main() {
	var tom Person
	tom = Person{
		id:101,
		name:"tom",
	}
	showPerson(tom)//last:{101 amy}
	fmt.Println("----------")
	fmt.Printf("%v\n", tom) //{101 tom}
	var per *Person
	per=&tom
	showPerson2(per)
	fmt.Printf("%v\n", tom) //{102 anna} tom被修改了
	
}

3.5golang中结构体的嵌套

golang没有面向对象编程思想,也没有继承关系,但是可以通过结构体嵌套来实现这种效果

package main

import (
	"fmt"
)
/*
golang结构体嵌套
*/
//定义
type Dog struct{
	name string
	color string
	age int
}
//Person中嵌套了Dog
type Person struct{
	dog Dog
	id int
	name string
}

func main() {
	var tom Person
	fmt.Printf("tom:%v", tom) //tom:{{  0} 0 }
	dog:=Dog{
		"xiaohuang",
			"huang",
			11,
	}
	tom=Person{
		dog,
		101,
		"tom",
	}
	fmt.Printf("tom:%v", tom) //tom:{{xiaohuang huang 11} 101 tom}
}

四、golang方法

go语言中的方法是一种特殊的函数,被称为struc的接收者

方法就是有接受者的函数

4.1语法

package main

import (
	"fmt"
)
/*
golang方法
*/
//定义
//Person中嵌套了Dog
type Person struct{
	name string
}
type Customer struct{
	name string
}
//属性和方法分开来写

//person 接收者receiver
func (person Person) eat(){
	fmt.Printf("%v,eat....\n", person.name)
}
func (person Person) sleep(){
	fmt.Printf("%v,sleep..\n", person.name)
}
func (cus Customer) login(name string,pwd string) bool{
	fmt.Printf("cus.name:%v\n", cus.name)
	if name==cus.name&&pwd=="123"{
		return true
	}else{
		return false
	}
}

func main() {
	per:=Person{
		"tom",
	}
	per.eat() //不能直接使用eat(),必须要有一个接收者。即per.eat()
	per.sleep()

	cus:=Customer{
		"zxx",
	}
	flag1:=cus.login("zxx","123")
	fmt.Printf("%v", flag1)
}

4.2 go语言方法的注意事项

4.3golang方法接收者类型

结构体实例有指针类型和值类型,那么方法的接收者是结构体,也有值类型和指针类型。区别就是接收者是否复制结构体副本。值类型复制但是指针类型不复制

package main

import (
	"fmt"
)
/*
golang方法
*/
//定义
//Person中嵌套了Dog
type Person struct{
	name string
}
func f1(){
	per1:=Person{
		"tom",
	}
	per2:=&Person{
		name:"tom",
	}
	fmt.Printf("per1:%T", per1) //main.Person
	fmt.Printf("per2:%T", per2) //*main.Person
}

func (per Person)showPerson1(){
	per.name="tom..."
}
func (per *Person)showPerson2(){
	//per.name  ----  自动解引用
	per.name="tom..."
}
func main() {
	p1:=Person{
		name:"tom",
	}
	p2:=&Person{
		name:"tom",
	}
	p1.showPerson1()
	fmt.Printf("p1:%v\n", p1)//p1:{tom}
	fmt.Printf("p2:%v\n", p2)//p2:&{tom}
	p2.showPerson2() //接收者是指针类型,就不会复制结构体副本,会修改本结构体
	fmt.Printf("p1:%v\n", p1)//p1:{tom}
	fmt.Printf("p2:%v\n", p2)//p2:&{tom...}

	
}


五、golang接口

接口像是一个公司里面的领导,会定义一些通用规范。只设计规范,而不实现规范

go语言的接口,是一种新的类型定义,它把所有的具有共性的方法定义在一起。任何其他类型只要实现了这些方法就是实现了这个接口

5.1接口的语法格式

示例

package main

import (
	"fmt"
)
/*
golang接口
*/
//个人理解:接口中包含着有共性的方法,比如电脑和手机都有USB接口
//对于USBer里面的方法,电脑和手机都可以实现
type USBer interface{
	read()
	write()
}
type Computer struct{
	name string
}
type Mobile struct{
	model string
}
func (c Computer) read(){
	fmt.Printf("c.name:%v\n", c.name)
	fmt.Println("read...")
}
func (c Computer) write(){
	fmt.Printf("c.name:%v\n", c.name)
	fmt.Println("write...")
}

// func (m Mobile) read(){
// 	fmt.Printf("m.name:%v\n", m.model)
// 	fmt.Println("read...")
// }
func (m Mobile) write(){
	fmt.Printf("m.name:%v\n", m.model)
	fmt.Println("write...")
}

func main() {
	c:=Computer{
		name:"my_computer",
	}
	c.read()
	c.write()

	m:=Mobile{
		model:"5G",
	}
	// m.read()
	m.write()
}


理解一下,接口本身没有直接性的功能,而是起到一个规范的作用

比如之前我们写过一些代码,我们想要调用之前的方法来实现一个功能,就需要单

独去找这些方法的位置,而接口就是将某个功能所需的所有方法放在一起,作为一个规范

其他人看到了接口内的方法名就知道要去找那些方法来实现功能了
————————————————
版权声明:本文为CSDN博主「默子昂」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.csdn.net/qq_42883074/article/details/123114736

 5.2golang接口 值类型和指针类型

package main

import (
	"fmt"
)
/*
golang接口值类型接收者和指针类型接收者
*/
type Pet interface{
	eat(string) string
	eat1(string) string
}

type Dog struct {
	name string
}
func (dog Dog) eat(name string) string{
	dog.name="huahua..."
	fmt.Printf("%v\n", name)
	return "吃的很好"
}
func (dog *Dog) eat1(name string) string{
	dog.name="huahua..."
	fmt.Printf("%v\n", name)
	return "吃的很好"
}
func main() {
	dog:=Dog{
		name:"huahua",
	}
	dog1:=&Dog{
		name:"huahua",
	}
	s:=dog.eat("huoji")
	s1:=dog1.eat1("huoji")
	fmt.Printf("s:%v\n", s)
	fmt.Printf("s1:%v\n", s1)
	fmt.Printf("dog:%v\n", dog)
	fmt.Printf("dog1:%v\n", *dog1) //dog1:{huahua...} 修改过了
}


5.3 golang接口和类型的关系

  1. 一个类型可以实现多个接口
  2. 多个类型可以实现同一个接口(多态)

一个类型实现多个接口

package main

import (
	"fmt"
)
/*
golang接口和类型的关系
*/
type Player interface {
	playMusic()
}
type Video interface {
	PlayVedio()
}
type Mobile struct {
	
}
func (m Mobile) playMusic(){
	fmt.Println("play music")
}
func (m Mobile) playVideo(){
	fmt.Println("play video")
}

func main() {
	//一个类型(Mobile)实现多个接口(Player、 Video)
	m:=Mobile{}
	m.playMusic()
	m.playVideo()
}


多个类型实现一个接口  

Comuputer和Mobile都实现了USBer接口

package main

import (
	"fmt"
)
/*
golang接口
*/
//个人理解:接口中包含着有共性的方法,比如电脑和手机都有USB接口
//对于USBer里面的方法,电脑和手机都可以实现
type USBer interface{
	read()
	write()
}
type Computer struct{
	name string
}
type Mobile struct{
	model string
}
func (c Computer) read(){
	fmt.Printf("c.name:%v\n", c.name)
	fmt.Println("read...")
}
func (c Computer) write(){
	fmt.Printf("c.name:%v\n", c.name)
	fmt.Println("write...")
}

func (m Mobile) read(){
	fmt.Printf("m.name:%v\n", m.model)
	fmt.Println("read...")
}
func (m Mobile) write(){
	fmt.Printf("m.name:%v\n", m.model)
	fmt.Println("write...")
}

func main() {
	c:=Computer{
		name:"my_computer",
	}
	c.read()
	c.write()

	m:=Mobile{
		model:"5G",
	}
	m.read()
	m.write()

	//真正意义上实现接口
	var usb USBer
	usb=Computer{
		name:"my_computer",
	} 
	usb.read()//c.name:my_computer read...
	usb=Mobile{
		model:"5G",
	}  
	//如果mobile中的read或者write方法没有全部实现的话,
	//说明没有成功继承这个接口
	//则usb=Mobile{}会报错
	usb.read() //m.name:5G read...

}


5.4 golang接口嵌套

接口可以通过嵌套,创建新的接口。例如:飞鱼,既可以飞,又可以游泳。我们创建一个fly接口,再创建一个游泳接口swim。飞鱼由这两个接口组成

package main

import (
	"fmt"
)
/*
golang接口嵌套
*/
type Fly interface {
	fly()
}
type Swim interface {
	swim()
}
type FlySwim interface {
	Fly
	Swim
}
func (fish Fish) fly(){
	fmt.Println("fly")
}
func (fish Fish) swim(){
	fmt.Println("swim")
}
type Fish struct {
}



func main() {
	var ff FlySwim
	ff=Fish{}
	ff.fly() //fly
	ff.swim() //swim
}


5.5 golang通过接口实现OCP设计原则

面向对象的可复用设计的第一块基石,就是所谓的”开闭“原则(open-closed Principle,缩写为OCP)。虽然go不是面向对象语言,但是也可以模拟实现这个原则

开闭原则:对扩展开放的,对修改关闭

示例:主任现在有两只宠物:猫和狗,他们都实现pet接口,完成吃和睡的工作。对于主任来说,只需要care(宠物)j即可,如果主人还有别的宠物,例如小猪,就可以另小猪实现pet接口,从而调用care(pig),只需要添加,不需要修改。如此就反映出了OCP原则,即对于扩展开放,对于修改关闭

package main

import (
	"fmt"
)
/*
golang OCP设计原则
*/

type Pet interface {
	eat()
	sleep()
}

type Dog struct {
}

type Cat struct {
}
//dog实现接口方法
func (dog Dog)eat(){
	fmt.Println("dog eat...")
}
func (dog Dog)sleep(){
	fmt.Println("dog sleep...")
}
//cat实现接口
func (cat Cat)eat(){
	fmt.Println("cat eat...")
}
func (cat Cat)sleep(){
	fmt.Println("cat sleep...")
}
type Person struct {
	
}

//pet既可以是cat也可使dog--向上类型转换
func (person Person) care(pet Pet){
	pet.eat()
	pet.sleep()
}


func main() {
	dog:=Dog{}
	cat:=Cat{}
	person:=Person{}
	person.care(dog) //dog eat... dog sleep...因为传递的是dog,所以向上类型转换成了dog
	person.care(cat) //cat eat... cat sleep... 因为传递的是cat,所以向上类型转换成了cat
	/*
	如果主人还有别的宠物,例如小猪,就可以另小猪实现pet接口,从而调用care(pig).
	如此就反映出了OCP原则,即对于扩展开放,对于修改关闭
	*/
}


5.6 golang中模拟OOP(面向对象)中的属性和方法

可以通过结构体函数绑定来实现,即加一个接收者receiver-----方法

package main

import (
	"fmt"
)
/*
golang 模拟OOP
*/

type Person struct {
	name string
	age int
}
func (per Person) eat(){
	fmt.Println("eat...")
}
func (per Person) sleep(){
	fmt.Println("sleep...")
}
func (per Person) work(){
	fmt.Println("work...")
}

func main() {
	per:=Person{
		name:"tom",
		age:11,
	}
	per.eat() //eat...
	per.sleep() //sleep...
	per.work() //work...

	
}


5.7golang继承

因为golang没有oop的概念,所以也没有继承的概念。但是可以通过结构体嵌套来实现

package main

import (
	"fmt"
)
/*
golang 继承
*/
type Animal struct {
	name string
	age int
}
func (a Animal)eat()  {
	fmt.Println("eat...")
}
func (a Animal)sleep()  {
	fmt.Println("sleep")
}

type Dog struct {
	a Animal  //可以理解为dog继承了animal
	color string
}

type Cat struct {
	a Animal  //可以理解为cat继承了animal
	color string
}
/*
cat和dog可以通过结构体嵌套这种方式
继承Animal中的属性(name,age)和方法(sleep,eat)
*/

func main() {
	//方式一:
	// dog:=Dog{
	// 	a:Animal{name:"huahua",age:2},
	// 	color:"yellow",
	// }
	// cat:=Cat{
	// 	a:Animal{name:"quanquan",age:3},
	// 	color:"blue",
	// }
	// dog.a.eat()
	// dog.a.sleep()
	// cat.a.eat()
	// cat.a.sleep()

	//方式二
	dog:=Dog{
		Animal{name:"huahua",age:2},
		"yellow",
	}
	cat:=Cat{
		Animal{name:"quanquan",age:3},
		"blue",
	}
	dog.a.eat()
	dog.a.sleep()
	cat.a.eat()
	cat.a.sleep()
	
}


5.8 golang构造函数

golang没有构造函数的概念,可以使用函数来模拟构造函数的功能

package main

import (
	"fmt"
)
/*
golang 构造函数
*/
type Person struct {
	name string
	age int
}

func NewPerson(name string,age int)(*Person,error){
	if name==""{
		return nil,fmt.Errorf("name 不能为空")
	}
	if age<0{
		return nil,fmt.Errorf("age 不能小于0")
	}
	return &Person{name:name,age:age},nil
}
func main() {
	per,err:=NewPerson("tom",11)
	if err==nil{
		fmt.Printf("per:%v\n", per) //per:&{tom 11}
	}else{
		fmt.Printf("err:%v\n", err)
	}

}


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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值