目录
一、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接口和类型的关系
- 一个类型可以实现多个接口
- 多个类型可以实现同一个接口(多态)
一个类型实现多个接口
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)
}
}