go的指针,结构体,方法,以及接口

1 指针

//指针:指针是一种存储变量内存地址(Memory Address)的变量。
package main

func main() {
	//1 定义指针
	// 指向int类型的指针(指向什么类型指针,就是在什么类型前加星号)
	//var a *int

	//2 指针的零值
	//fmt.Println(a)

	//3 使用指针
	//var a *int
	//var b int=100
	////a指针指向b  (取谁的地址,就是在谁前面加一个&)
	//a=&b
	//fmt.Println(a)
	//
	////4 了解(骚操作)
	////var c =&a
	//var c **int=&a
	//var d ***int =&c
	//fmt.Println(d)
	//
	////5 解引用(把指针反解成值)  (在指针变量前加*,表示解引用)
	//fmt.Println(*a)
	//fmt.Println(***d)

	//6 向函数传递指针参数
	//var a int =100
	////在函数中把a的值改成101
	//fmt.Println(a)
	//test2(&a)
	//fmt.Println(a)

	//7 不要向函数传递数组的指针,而应该使用切片
	//var a [4]int  = [4]int{1,2,3}
	//fmt.Println(a)
	////test3(&a)
	//test4(a[:])
	//fmt.Println(a)

	//8 go不支持指针运算
	//var b int=100
	//var a *int=&b
	//
	//a++

	//9 指针数组和数组指针
	//指针数组---->数组里面放指针
	//var a int =10
	//var b int =20
	//var c int =30
	//var d [3]*int=[3]*int{&a,&b,&c}
	//fmt.Println(d)

	//数组指针----》指向数组的指针
	//var a [3]int=[3]int{1,3,4}
	//var b *[3]int=&a
	//fmt.Println(b)





}
//func test2(a *int)  {
//	//解引用然后,自增1
//	//*a++
//	*a=*a+100
//	fmt.Println(*a)
//}

//func test3(a *[3]int)  {
//	//(*a)[0]=999
//	//神奇的一幕(go语言处理了一层,如果是数组的指针,直接像操作数组操作就可以了)
//	a[0]=999
//	//a是地址,如果是数组的地址,会显示成 &[999 2 3]
//	fmt.Println(a)
//}
//
//func test4(a []int)  {
//	a[0]=999
//	fmt.Println(a)
//}

2 结构体

//结构体,go语言中的面向对象
//结构体是用户定义的类型,表示若干个字段(Field)的集合
//类比面向对象中的类,只有属性,没有方法


package main

import "fmt"

//1 定义一个人类结构体(名字,年龄,性别属性)
// type关键字 结构体名字 struct关键字 {一个一个的字段}
//type Person struct {
//	name string
//	age int
//	sex string
//}

//7 匿名字段(字段没有名字,不允许有多个同类型的字段)
//type Person struct {
//	 string
//	 int
//	 //int
//	 sex string
//	 //sex string
//}

//8 嵌套结构体(结构体套结构体)
//不管是结构体名字还是字段名字,大写字母开头,表示导出字段,表示在外部包可以使用
//面向对象封装(python __)
//type Person struct {
//	Name string
//	Age int
//	Sex string
//	hobby Hobby
//}
//type Hobby struct {
//	HobbyId int
//	HobbyName string
//}


//// 9 提升字段
//type Person struct {
//	Name string
//	Age int
//	Sex string
//	Hobby
//}
//type Hobby struct {
//	HobbyId int
//	HobbyName string
//}

// 10 字段冲突
type Person struct {
	Name string
	Age int
	Sex string
	Hobby
}
type Hobby struct {
	HobbyId int
	Name string
}
func main() {
	//2 使用结构体(结构体的零值,是属性的零值)不是nil,它不是引用类型,是值类型
	//var a Person
	//fmt.Println(a)

	//3 定义并初始化
	//var a Person=Person{}
	//var a Person=Person{name:"lqz",age:19,sex:"男"}
	//var a =Person{name:"lqz",age:19,sex:"男"}
	//a :=Person{name:"lqz",age:19,sex:"男"}
	//a :=Person{sex:"男",name:"lqz",age:19}
	//a :=Person{sex:"男",name:"lqz"}
	//按位置初始化(固定位置,并且都传)
	//a :=Person{"lqz",19,"男"}
	//fmt.Println(a)

	//4 使用结构体(通过 . 取值)
	//var a Person=Person{name:"lqz",age:19,sex:"男"}
	//fmt.Println(a.name)
	//a.name="egon"
	//fmt.Println(a)

	//5 匿名结构体(没有名字,没有type关键字,定义在函数内部)
	//什么情况下用?只使用一次,数据整合在一起
	//a:=struct {
	//	name string
	//	age int
	//	sex string
	//}{"lqz",19,"男"}
	//fmt.Println(a.name)

	//6 结构体的指针(因为结构体是值类型)
	//var a *Person=&Person{"lqz",19,"男"}
	//fmt.Println(a)
	////Go 语言允许我们在访问 字段时,可以使用 emp8.firstName 来代替显式的解引用 (*emp8).firstName
	//fmt.Println((*a).name)
	//fmt.Println(a.name)

	//7 匿名字段(字段没有名字)(有什么用?用来做字段提升,面向对象中的继承)
	//按位置实例化
	//a:=Person{"lqz",19}
	//按关键字实例化
	//a:=Person{int:19,string:"lqz"}
	//fmt.Println(a)
	//fmt.Println(a.string)
	//fmt.Println(a.int)

	//8 嵌套结构体(结构体套结构体)
	//按位置
	//var a Person  = Person{"lqz",19,"男",Hobby{1,"篮球"}}
	//按关键字
	//var a Person  = Person{hobby:Hobby{HobbyName:"篮球"}}
	//fmt.Println(a)
	//fmt.Println(a.hobby.HobbyName)

	//9 提升字段
	//a:=Person{Hobby:Hobby{1,"篮球"}}
	//fmt.Println(a.HobbyName)
	//fmt.Println(a.HobbyId)
	//fmt.Println(a.Hobby.HobbyId)
	//相当于Person继承了Hobby,
	//a.父类的属性:a.HobbyId
	//super().父类属性:a.Hobby.HobbyId

	//10 字段重复(父类跟子类是属性冲突)
	//a:=Person{Hobby:Hobby{1,"篮球"}}
	//fmt.Println(a.Name) // 用了Person的Name
	//fmt.Println(a.Hobby.Name) // 相当于 super().属性

	//11 导出结构体和字段 (用大写字母开头,表示外部包可以使用)

	//12 结构体相等性(了解一下),值类型,支持比较
	//结构体是值类型。如果它的每一个字段都是可比较的,则该结构体也是可比较的。 如果两个结构体变量的对应字段相等,则这两个变量也是相等的
	//如果结构体包含不可比较的字段(切片,map。。。引用类型),则结构体变量也不可比较

	//13 结构体当参数传递
	a:=Person{Hobby:Hobby{1,"篮球"}}
	fmt.Println(a)
	//test5(a)  // 传递的是值,就不会改变原来的
	test6(&a)
	fmt.Println(a)

}
func test5(a Person){
	a.Name="xxx"
	fmt.Println(a)
}
func test6(a *Person){
	//a.Name="xxx"
	(*a).Name="xxx"
	fmt.Println(a)
}

3 方法


// 结构体+方法实现面向对象中的类

//方法

//方法其实就是一个函数,在 func 这个关键字和方法名中间加入了一个特殊的接收器类型。接收器可以是结构体类型或者是非结构体类型。接收器是可以在方法的内部访问的

//python中什么是方法,什么是函数?
//函数就是定义的普通函数
//方法是面向对象中的概念,对象绑定方法,类的绑定方法,可以自动传值,
//类中不加任何装饰器定义的函数,是对象的绑定方法,对象来调用,可以自动传值,类也可以来掉,如果类来调用,他就是普通函数,有几个值就传几个值
//类的绑定方法,类来调用,会把类自动传入

package main

import "fmt"

//1 定义方法
//定义一个结构体
//type Person1 struct {
//	name string
//	age int
//	sex string
//}
////给结构体绑定方法
//func (p Person1)PrintName()  {
//	fmt.Println(p.name)
//}
//
////绑定一个修改名字的方法
//func (p Person1)ChangeName(name string)  {
//	p.name=name
//	fmt.Println("--------",p)
//}
//
////指针类型接收器,修改age的方法
//func (p *Person1)ChangeAge(age int)  {
//	p.age=age
//	//(*p).age=age   //正常操作
//	fmt.Println("--------",p)
//}
//
//
////普通函数
//func PrintName(p Person1)  {
//	fmt.Println(p.name)
//}



//5 匿名字段的方法(重点)
//type Hobby1 struct {
//	id int
//	hobbyName string
//}
//type Person1 struct {
//	name string
//	age int
//	sex string
//	Hobby1  //匿名字段
//}
////给Hobby1,绑定一个打印名字的方法
//func (h Hobby1)printName()()  {
//	fmt.Println(h.hobbyName)
//}
//
////给Person1绑定一个方法(相当于重写了父类方法)
//func (p Person1)printName()()  {
//	//即打印hobby的名字,又打印人的名字
//	//fmt.Println(p.hobbyName)
//	//fmt.Println(p.Hobby1.hobbyName)
//	//直接调用Hobby1的方法(调用父类方法,相当于 super().方法名)
//	p.Hobby1.printName()
//	fmt.Println(p.name)
//}

////6 在方法中使用值接收器 与 在函数中使用值参数
//type Person1 struct {
//	name string
//	age int
//	sex string
//}
////方法中使用值接收器
//func (p Person1)printName()  {
//	fmt.Println(p.name)
//}
////在函数中使用值参数
//func printName(p Person1)  {
//	fmt.Println(p.name)
//}


//7 在方法中使用指针接收器 与 在函数中使用指针参数
//type Person1 struct {
//	name string
//	age int
//	sex string
//}
////在方法中使用指针接收器
//func (p *Person1)printName()  {
//	fmt.Println(p.name)
//}
////在函数中使用指针参数
//func printName(p *Person1)  {
//	fmt.Println(p.name)
//}


//8 在非结构体上的方法
// 不可以
//func (i int)add()  {
//	i=i+i
//}

//自己定义的类型,可以绑定方法
type myInt int
//给自己定义的类型绑定方法
func (i *myInt)add()  {
	(*i)++
	fmt.Println(*i)
}

func main() {
	// 1 方法的定义和使用
	//p:=Person1{"lqz",19,"男"}
	//p.PrintName()

	//PrintName(p)  // 需要手动来传,跟结构体没有必然联系

	//2 为什么我们已经有函数了还需要方法呢

	//3 值接收器和指针接收器
	//p:=Person1{"lqz",19,"男"}
	//p.ChangeName("egon")  // 值接收器,改新的,不会影响原来的,不会影响当前的p对象
	//fmt.Println(p)
	//调用指针类型接收器的方法
	//p.ChangeAge(100)  //指针类型接收器,会影响原来的,会影响当前的p对象
	//fmt.Println(p)

	//4 那么什么时候使用指针接收器,什么时候使用值接收器?
	//用指针接收器的情况
	//1 方法内部的改变,影响调用者
	//2 当拷贝一个结构体的代价过于昂贵时 ,就用指针接收器
	//其他情况,值接收器和指针接收器都可以


	//5 匿名字段的方法(重点)
	//p:=Person1{"lqz",19,"男",Hobby1{1,"篮球"}}
	////匿名字段,属性可以提升
	////匿名字段,方法也提升
	////p.printName()  // 也提升了  子类对象调用父类中的方法,子类中没有,就是调用父类的--》 对象.方法名
	////p.Hobby1.printName() // 正常操作 直接指名道姓的调用父类中的方法---》 super().方法名
	//
	////子类中重写了父类的方法(嵌套结构体中有重名的方法)
	//p.printName()

	//6  在方法中使用值接收器 与 在函数中使用值参数
	//p:=Person1{"lqz",19,"男"}
	//p.printName()
	//printName(p)
	//神奇的一幕
	//p 是指向结构体的指针
	//p:=&Person1{"lqz",19,"男"}
	//p.printName()
	////printName(p)
	//printName(*p) //解引用



	//7  在方法中使用指针接收器 与 在函数中使用指针参数
	//p:=&Person1{"lqz",19,"男"}
	//	//p.printName()
	//	//printName(p)
	//相应的
	//p:=Person1{"lqz",19,"男"}
	//p.printName()
	////printName(p)
	//printName(&p)

	//不论值类型接收器还是指针类型接收器,都可以使用值来调,也可以使用指针来调


	//8 在非结构体上的方法
	//i:=10
	//i.add()

	var i myInt =10
	fmt.Println(i)
	i.add()
	i.add()
	i.add()
	i.add()
	i.add()
	fmt.Println(i)


}


// 链式调用

4 接口入门

//接口
//接口定义一个对象的行为。接口只指定了对象应该做什么,至于如何实现这个行为(即实现细节),则由对象本身去确定。

//django框架频率组件 Base--》根据ip过滤的,自己写频率组件,必须继承base,如果没有实现Base中的所有方法,就报错
//abc模块,强制要求子类必须重写某些方法
package main


//1 定义接口(接口是一系列行为的集合:一系列方法的集合)

type Duck interface {
	run()
	speak()
}
//只要结构体绑定了接口中的所有方法,这个结构体就叫实现了Duck接口
type TDuck struct {
	name string
	age int
	wife string
}
//实现Duck接口(绑定接口中的所有方法)
func (t TDuck)run()  {

}
func (t TDuck)speak()  {

}

补充

1 链式调用

# 对象.修改名字(lqz).修改年龄(10)
# 一门语言如何实现链式调用
class Person:
	def chang_name(self,nane):
    self.name=name
    return self
	def chang_age(self,age):
    self.age=age
    return self
posted @ 2020-05-03 23:32  alen_zhan  阅读(622)  评论(0编辑  收藏  举报
返回顶部