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
Only you can control your future
You're not alone. You still have family,peopel who care for you and want to save you.