结构体
package main
import "fmt"
//结构体:一系列属性的集合
//定义结构体(在包中定义了)
//7 定义一个结构体,内涵匿名字段(字段没有名字) 匿名字段类型就是字段名,所有类型不能重复
//type Person struct {
// string
// int
// sex string
//}
//8 嵌套结构体(结构体中套结构体)
//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
//}
//type Person struct {
// Name string
// Age int
// sex string
// Hobby
//}
//type Hobby struct {
// Id int
// Name string
//}
//11 结构体相等性
type Person struct {
Name string
Age int
sex string
//包含不可比较的字段
AAA []int
}
func main() {
//1 结构体的使用 值类型
//var per entity.Person
//fmt.Println(per)
//per.Name="lqz"
//per.Age=19
//fmt.Println(per)
//2 定义并赋初值
//var per entity.Person=entity.Person{Name:"lqz"} //不按位置,少传
//var per2 entity.Person=entity.Person{"lqz",19,"男"} //按位置,全穿
//fmt.Println(per2)
//per2.Age=20
//fmt.Println(per2)
//3 匿名结构体(定义在内部(函数,结构体),只使用一次,没有名字)
// 有什么用?当定义多个变量(想一次使用),就可以把这多个变量放到匿名结构体中
//a := struct {
// HobbyId int64
// HobbyName string
//}{HobbyId: 1, HobbyName: "篮球"}
//
//fmt.Println(a.HobbyName)
//a.HobbyName="足球"
//fmt.Println(a.HobbyName)
//4 结构体的零值,值类型
//var per entity.Person
//fmt.Println(per) //属性的零值,值类型,参数传递,copy传递,在函数中修改,不会影响原来的
//test2(per)
//fmt.Println(per)
//5 访问结构体字段 ,通过 . 来访问 注意大小写
//6 结构体的指针
//var per *entity.Person
//fmt.Println(per)
//定义并初始化
//var per *entity.Person=&entity.Person{}
//fmt.Println(per)
////把per的名字改成lqz
//(*per).Name="lqz"
////支持直接使用(数组也是这样,自动帮你处理了)
//per.Name="egon"
//fmt.Println(per)
//7 匿名字段(字段没有名字,只有类型)
//【变量提升/提升字段】面向对象的继承
//per:=Person{"lqz",19,"男"}
//per:=Person{string:"lqz",int:19,sex:"男"} //字段匿名,类型就是字段名
//fmt.Println(per)
//fmt.Println(per.string)
//fmt.Println(per.int)
//8 嵌套结构体(结构体中套结构体)
//var per Person =Person{"lqz",19,"男",Hobby{1,"篮球"}}
//var per Person =Person{Name: "lqz",Age: 19,sex: "男"}
//var per Person =Person{Name: "lqz",Age: 19,sex: "男",Hobby:Hobby{1,"足球"} }
//var per Person =Person{Name: "lqz",Age: 19,sex: "男",Hobby:Hobby{HobbyId: 1,HobbyName: "足球"}}
//fmt.Println(per.Name)
//fmt.Println(per.Hobby.HobbyName)
//9 字段提升
//var per Person =Person{"lqz",19,"男",Hobby{1,"篮球"}}
//var per Person =Person{Name: "lqz",Age: 19,sex: "男",Hobby:Hobby{HobbyId: 1,HobbyName: "足球"}}
////打印爱好的名字(Hobby是一个匿名字段,会字段提升)
//fmt.Println(per.HobbyName)
//fmt.Println(per.Hobby.HobbyName) //per.Hobby 类似于面向对象中的super()
////像什么?像面向对象的继承 子类继承父类(结构体嵌套,匿名字段),子类可以直接调用父类中的属性或方法
//var per Person =Person{Name: "lqz",Age: 19,sex: "男",Hobby:Hobby{ 1, "足球"}}
//fmt.Println(per.Name) //优先使用自己的
////打印出hobby的名字
//fmt.Println(per.Hobby.Name)
//10 导出结构体和字段 大写字母开头,在外部包可以使用
//11 结构体相等性
//结构体是值类型。
//如果它的每一个字段都是可比较的,则该结构体也是可比较的。 如果两个结构体变量的对应字段相等,则这两个变量也是相等的
//如果结构体包含不可比较的字段,则结构体变量也不可比较。
//值类型,可以直接==比较,引用类型只能跟nil用==比较
//per1:=Person{Name: "lqz"}
//per2:=Person{Name: "lqz",Age:19}
//fmt.Println(per1==per2)
//per1:=Person{Name: "lqz"}
//per2:=Person{Name: "lqz",Age:19}
//fmt.Println(per1==per2) //包含不可比较的属性
fmt.Println("lqz nb")
}
//func test2(per entity.Person) {
// per.Age=99
// fmt.Println(per)
//}
方法
package main
//方法:特殊函数,在函数的基础上加了一些东西
//在 func 这个关键字和方法名中间加入了一个特殊的接收器类型,接收器可以是结构体类型,也可以是非结构体类型
//type Person2 struct {
// Name string
// Age int
// Sex string
//}
//
////def add(self):
//// self.name
//// pass
////定义一个方法 : (p Person2) 绑定给了Person2结构体的对象
//func (p Person2) printName() {
// //在方法内可以使用p
// fmt.Println(p.Name)
//}
////修改名字
//func (p Person2) changeName(name string) {
// p.Name=name
// fmt.Println(p)
//}
////修改年龄方法
//func (p *Person2) changeAge(age int) {
// //fmt.Println(p.Age) //推荐用这个
// p.Age=age
//}
//
//func printName(p Person2) {
// fmt.Println(p.Name)
//}
// 匿名字段的方法
//type Person2 struct {
// Name string
// Age int
// Sex string
// Hobby //匿名字段
//}
//type Hobby struct {
// Id int
// Name string
//}
//
////给结构体绑定方法
//func (p Person2)printName() {
// fmt.Println(p.Name)
//}
////func (h Hobby)printHobbyName() {
//func (h Hobby)printName() {
// fmt.Println(h.Name)
//}
/// //6 在方法中使用值接收器 与 在函数中使用值参数
//type Person2 struct {
// Name string
// Age int
// Sex string
//}
////在方法中使用值接收器
//func (p Person2)printName() {
// fmt.Println(p.Name)
//}
//func (p Person2)changeName(name string) {
// p.Name=name
// fmt.Println(p)
//}
////在函数中使用值参数
//func printName(p Person2) {
// fmt.Println(p.Name)
//}
//7 在方法中使用指针接收器 与 在函数中使用指针参数
//type Person2 struct {
// Name string
// Age int
// Sex string
//}
////在方法中使用值接收器
//func (p *Person2)printName() {
// fmt.Println(p.Name)
//}
//func (p *Person2)changeName(name string) {
// p.Name=name
// fmt.Println(p)
//}
////在函数中使用指针参数
//func printName(p *Person2) {
// //fmt.Println((*p).Name)
// fmt.Println(p.Name)
//}
//8 非结构体上的方法(不允许)自己定义的类型可以绑定方法
//在int类型上绑定一个add方法
//不允许
//func (i int)add(){
// i=i+1
// i++
// //i+=1
//}
// 可以在自定义的类型上绑定方法
type Myint int
func (i *Myint)add(){
(*i)=(*i)+1
//i++
//i+=1
}
func main() {
//1 方法的定义和使用
//per:=Person2{}
//per.Name="lqz"
//per.printName() //绑定给对象的方法
//
//per1:=Person2{Name: "egon"}
//per1.printName()
//2 为什么我们已经有函数了还需要方法呢?
//per1:=Person2{Name: "egon"}
////per1.printName() //方法的特殊之处,可以自动传值
////
////printName(per1)
//per1.changeName("lqz")
//
////并没有改
//fmt.Println(per1)
//3 指针接收器与值接收器
//per1:=Person2{Name: "egon",Age: 18}
//fmt.Println(per1)
//per1.changeAge(99)
//fmt.Println(per1)
//4 时候使用指针接收器,什么时候使用值接收器:想改原来的,就用指针,不想改原来的就用值(指针用的多)
//5 匿名字段的方法(方法提升)
//per1:=Person2{Name: "lqz",Hobby:Hobby{1,"足球"}}
////per1.printHobbyName() //Hobby是个匿名字段,方法也提升了
////如果方法名冲了,优先用该结构体自己的
//per1.printName()
//per1.Hobby.printName()
//6 在方法中使用值接收器 与 在函数中使用值参数
//per1:=Person2{Name: "lqz"}
//per1.printName()
//printName(per1)
//per1:=&Person2{Name: "lqz"} //per1是个指针
//per1.printName()
//printName(*per1)
//小研究
//per1:=&Person2{Name: "lqz"} //per1是个指针
//per1.changeName("egon")
//fmt.Println(per1)
//值收器:可以用值来调,也可以用指针来调
//函数的值参数,只能传值
//7 在方法中使用指针收器 与 在函数中使用指针参数
//per1:=Person2{Name: "lqz"}
//per1.printName() //值可以来调用
//printName(&per1)
//per1:=&Person2{Name: "lqz"}
//per1.printName() //指针可以来调用
//printName(per1)
//小研究
//per1:=Person2{Name: "lqz"}
//per1.changeName("egon")
//fmt.Println(per1)
//per1:=&Person2{Name: "lqz"}
//per1.changeName("egon")
//fmt.Println(per1)
//总结:不管是值类型接收器还是指针类型接收器,都可以用值来调用,或者指针来调用
//总结:不管是值还是指针来调用,只要是值类型接收器,改的就是新的,只要是指针类型接收器,改的是原来的
//a:=1
//a+=1
//a++
//a=a+1
//++a //java中有++a
//fmt.Println(a)
//8 非结构体上绑定方法
//var a Myint =10
//fmt.Println(a)
//a.add()
//a.add()
//a.add()
//a.add()
//fmt.Println(a)
//
//var b =11
////fmt.Println(a+b) //类型不匹配
//
//c:=a+Myint(b)
//fmt.Println(a+Myint(b)) //类型匹配
//d:=int(a)+b
//fmt.Println(int(a)+b) //类型匹配
}
接口
package main
//go也是鸭子类型:我现在有个鸭子类,内有speak方法 有run方法, 子类只要实现了speak和run,我就认为子类是鸭子
//在java中,子类必须实现鸭子类的所有方法,子类才叫鸭子
//接口:面向对象的领域里,接口一般这样定义:接口定义一个对象的行为,规范子类对象的行为
//接口:是一系列方法的集合(规范行为)
//1 定义接口(定义一个鸭子接口,speak方法,run方法)
//type Duck interface {
// speak() //speak()方法
// run()
//}
//
////定义一个普通鸭子结构体
//type PDuck struct {
// name string
// sex string
// age int
//}
//
////定义一个唐老鸭结构体
//type TDuck struct {
// name string
// sex string
// age int
// wife string
//}
////让唐老鸭和普通鸭子都实现Duck接口
////结构体实现一个接口:只要绑定接口中的所有方法,就叫实现该接口
//func (p PDuck)speak() {
// fmt.Println("普通鸭子嘎嘎叫,普通鸭子名字叫",p.name)
//}
//func (p PDuck)run() {
// fmt.Println("普通鸭子歪歪扭扭走了,普通鸭子名字叫",p.name)
//}
//
////唐老鸭也实现Duck接口
//func (p TDuck)speak() {
// fmt.Println("唐老鸭说人话,唐老鸭子名字叫",p.name)
//}
//func (p TDuck)run() {
// fmt.Println("唐老鸭人走路,唐老鸭子名字叫",p.name)
//}
//
//
////6 空接口定义
//type Empty interface {
//}
func main() {
//1 得到一个普通鸭子对象
//pduck:=PDuck{"黑子","男",1}
//pduck.run()
//pduck.speak()
////2 得到一个堂老鸭子对象
//tduck:=TDuck{"egon","男",1,"刘亦菲"}
//tduck.run()
//tduck.speak()
//侵入式接口(接口没了,子类报错)和非侵入是接口(接口没了,不影响代码,go语言中的接口是非侵入式的)
//2 接口的实际用途(接口也是一个类型)
//var duck Duck
////pduck:=PDuck{"黑子","男",1}
//tduck:=TDuck{"egon","男",1,"刘亦菲"}
////duck=pduck
//duck=tduck //多态,同一类事务多种形态
//duck.run()
//3 接口内部表示
//我们可以把接口看作内部的一个元组 (type, value)。
//type 是接口底层的具体类型(Concrete Type),而 value 是具体类型的值。
//4 把接口类型转成struct,属性,自有方法也有了,类型断言
//类型断言
//var duck Duck =TDuck{"egon","男",1,"刘亦菲"}
////断言是TDuck类型
////v, ok := duck.(TDuck)
//////断言成功,ok是true,v就是TDuck结构体对象
////fmt.Println(v)
////fmt.Println(v.name)
////fmt.Println(ok)
//
////断言失败
//var v PDuck
//var ok bool
//v, ok = duck.(PDuck)
////断言失败,ok是false,v是PDuck类型的空置,因为没有复制
//fmt.Println(ok)
//fmt.Println(v)
//5 类型选择(通过switch)
//var duck Duck =TDuck{"egon","男",1,"刘亦菲"}
////var duck Duck =PDuck{"egon","男",1}
//test4(duck)
//6 空接口(没有任何方法,所有数据类型都实现了空接口)
//var a int=10
//var b string="lqz"
//var c [3]int
//var e Empty //空接口类型
//e=a
//e=b
//e=c
//fmt.Println(e)
//fmt.Println(1,"xxx")
//test5(a)
//test5(b)
//test5(c)
//7 匿名空接口 没有名字的空接口 一般用在形参上
//test6(10)
//test6("lll")
//var duck TDuck =TDuck{"egon","男",1,"刘亦菲"}
//test6(duck)
//8 之前学过的集合类型,都可以放接口类型
//var a[3]Duck
//a[1]=PDuck{}
//a[2]=TDuck{}
//var a map[string]interface{}= make(map[string]interface{})
//a["name"]="lqz"
//a["age"]=19
//a["duck"]=PDuck{}
}
//func test6(b interface{}) {
// fmt.Println(b)
//}
//func test5(b Empty) {
// switch v:=b.(type) {
// case string:
// fmt.Println("我是字符串")
// fmt.Println(v)
// case int:
// fmt.Println("我是int")
// fmt.Println(v)
// case [3]int:
// fmt.Println("我是数组")
// fmt.Println(v)
// }
//}
//func test4(duck Duck) {
// if v,ok:=duck.(TDuck);ok{
// fmt.Println("我是普通鸭子")
// fmt.Println(v)
// }else if v,ok:=duck.(PDuck);ok {
// fmt.Println("我是普通鸭子")
// fmt.Println(v)
// }
//}
//使用switch,选择成功,拿到结构体对象
//func test4(duck Duck) {
// switch v:=duck.(type) {
// case PDuck:
// fmt.Println(v.name)
// fmt.Println("我是普通鸭子")
// case TDuck:
// fmt.Println(v.wife)
// fmt.Println("我是唐老鸭")
// default:
// fmt.Println(v)
// fmt.Println("我是鸭子这个类")
//
// }
//}
make和new的区别
package main
//make和new的区别
type PDuck1 struct {
name string
sex string
age int
}
func main() {
//make是引用类型初始化的时候用的
//var per *PDuck1 =new(PDuck1) //new 是返回指向这个类型的指针
//fmt.Println(per)
//
//
//var per1 =&PDuck1{}
//fmt.Println(per1)
//var per2 = make([]int,3,4) //make是具体的造引用类型 //new是造指向这个类型的指针
//var per2 *[]int= new([]int)
//fmt.Println(per2)
//(*per2)=append((*per2),99)
//fmt.Println(per2)
}
结构体取代类
package main
import (
person "day04/Person"
"fmt"
)
func main() {
per :=person.New("lqz",19,"男")
//var per Person = new Person("lqz",19,"男")
fmt.Println(per)
per.PrintName()
}