Go 结构体 方法 接口
结构体
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() }