go基本语法总结
结构体(struct):
- 多个父类结构体继承
//父类 type person04 struct { name string age int sex string } //父类 type Person04 struct { id int addr string } //子类 type Student04 struct { //结构体成员为多个匿名字段 Person04 //匿名字段 person04 score int } func main() { var stu Student04 stu.id = 200 stu.addr = "北京" stu.name = "王富贵" stu.age = 10 stu.sex = "男" stu.score = 100 fmt.Println(stu) //自动推导类型 s := Student04{Person04{200,"北京"},person04{"王富贵",10,"男"},100} fmt.Println(s) }
//爷 type humen struct { id int name string } //父 type person05 struct { humen //匿名字段 age int sex string } //子 type student05 struct { person05 //匿名字段 score int } func main() { var stu student05 stu.name = "亚索" stu.sex = "男" stu.score = -5 fmt.Println(stu) //初始化 //自动推导类型 stu1 := student05{person05{humen{1001,"亚索"},30,"男"},-5} fmt.Println(stu1) }
- 定义结构体方法(可普通,可指针)
type cat struct { name string age int } type dog struct { name string age int } //函数定义 //func 函数名 (参数列表) 返回值列表 { // 代码体 //} func show() { fmt.Println("喵喵叫") } //方法定义 //func (对象)方法 (参数列表) 返回值列表 { // 代码体 //} //方法 //结构体类型 可以作为对象类型 //结构体作为接收者 func (c cat)show() { fmt.Println("喵喵叫") fmt.Printf("我是%s,喵喵叫\n",c.name) } //方法名一样 接受者不一样 方法也就不一样 func (d *dog)show() { fmt.Println("汪汪叫") } func main() { //对象创建 var c cat c.name = "小花" c.age = 2 fmt.Println(c) //对象.方法 包.函数 结构体.成员 c.show() //函数调用 //show() var d dog d.name = "旺财" d.age = 3 fmt.Println(d) d.show() //对象的方法名和函数名可以 重名 但是 相同的对象方法不能重名 //show() }
- 子类可以调用父类的方法
//父类 type person08 struct { id int name string age int } //子类 type student08 struct { person08 //匿名字段 class int } // 建议 使用指针类型 func (p *person08)PrintInfo() { fmt.Printf("编号%d\n",p.id) fmt.Printf("姓名%s\n",p.name) fmt.Printf("年纪%d\n",p.age) } func main() { p := person08{110,"德玛",30} p.PrintInfo() //子类可以继承父类 可以继承属性 和 方法 //父类不能继承子类 属性 方法 s := student08{person08{120,"德邦",15},9} s.PrintInfo() }
- 子类可以重构父类的方法,并且父类和子类的方法都可以保留下来,具体要看看是什么调用
type person09 struct { id int name string age int } // 建议 使用指针类型 func (p *person09) PrintInfo() { fmt.Printf("编号%d\n", p.id) fmt.Printf("姓名%s\n", p.name) fmt.Printf("年纪%d\n", p.age) } //子类 type student09 struct { person09 //匿名字段 class int } func (s *student09) PrintInfo() { fmt.Println("Student:", *s) } func main() { s := student09{person09{130, "小刚", 18}, 10} //子类对象方法 采用就近原则 使用子类的方法 //方法重写 s.PrintInfo() //父类对象方法 s.person09.PrintInfo() fmt.Println(s.PrintInfo) fmt.Println(s.person09.PrintInfo) }
- 方法可以赋值一个变量,然后让变量执行,达到隐藏结构体调用方法的效果
type person10 struct { id int name string age int } func (p person10) PrintInfo1() { fmt.Printf("info1%p, %v\n", &p, p) } //建议使用 func (p *person10) PrintInfo2() { fmt.Printf("info2%p, %v\n", p, *p) } func main() { p := person10{1, "make", 22} //p.PrintInfo1() //0xc042002400, {1 make 22} //p.PrintInfo2() //0xc0420023e0, {1 make 22} //fmt.Println(p.PrintInfo1) //fmt.Println(p.PrintInfo2) // //fmt.Printf("%T\n",p.PrintInfo1) //fmt.Printf("%T\n",p.PrintInfo2) //方法值 隐式传递 隐藏的是接受者 绑定实例(对象) //var pfunc1 func() //对象相同 但是函数类型不同 不能赋值 //函数类型相同 可以赋值 pfunc1 := p.PrintInfo1 pfunc1 = p.PrintInfo2 pfunc1() // == p.PrintInfo1 fmt.Printf("%T\n", pfunc1) //方法表达式 显式传参 //pfunc1 := person10.PrintInfo1 //pfunc1(p) //pfunc2 := (*person10).PrintInfo2 //pfunc2(&p) // // //fmt.Printf("%T\n",pfunc1) //fmt.Printf("%T\n",pfunc2) }
接口(interface):
- 接口不在结构体内创建,是单独的一种类型
//先定义接口 一般以er结尾 根据接口实现功能 type Humaner interface { //方法 方法的声明 sayhi() } type student11 struct { name string age int score int } func (s *student11)sayhi() { fmt.Printf("大家好,我是%s,今年%d岁,我的成绩%d分\n",s.name,s.age,s.score) } type teacher11 struct { name string age int subject string } func (t *teacher11)sayhi() { fmt.Printf("大家好,我是%s,今年%d岁,我的学科是%s\n",t.name,t.age,t.subject) } func main() { //接口是一种数据类型 可以接收满足对象的信息 //接口是虚的 方法是实的 //接口定义规则 方法实现规则 //接口定义的规则 在方法中必须有定义的实现 var h Humaner stu := student11{"小明",18,98} //stu.sayhi() //将对象信息赋值给接口类型变量 h = &stu h.sayhi() tea := teacher11{"老王",28,"物理"} //tea.sayhi() //将对象赋值给接口 必须满足接口中的方法的声明格式 h = &tea h.sayhi() }
- 接口可以作为参数放入方法里,从而实现多态
//先定义接口 一般以er结尾 根据接口实现功能 type Humaner1 interface { //方法 方法的声明 sayhi() } type student12 struct { name string age int score int } func (s *student12)sayhi() { fmt.Printf("大家好,我是%s,今年%d岁,我的成绩%d分\n",s.name,s.age,s.score) } type teacher12 struct { name string age int subject string } func (t *teacher12)sayhi() { fmt.Printf("大家好,我是%s,今年%d岁,我的学科是%s\n",t.name,t.age,t.subject) } //多态的实现 //将接口作为函数参数 实现多态 func sayhello(h Humaner1) { h.sayhi() } func main() { stu := student12{"小明",18,98} //调用多态函数 sayhello(&stu) tea := teacher12{"老王",28,"Go"} sayhello(&tea) }
- 子接口可以给父接口赋值,反之不行(因为子接口实现的方法多,方法只能多不能少)
//先定义接口 一般以er结尾 根据接口实现功能 type Humaner2 interface { //子集 //方法 方法的声明 sayhi() } type Personer interface { //超集 Humaner2 //继承sayhi() sing(string) } type student13 struct { name string age int score int } func (s *student13)sayhi() { fmt.Printf("大家好,我是%s,今年%d岁,我的成绩%d分\n",s.name,s.age,s.score) } func (s *student13)sing(name string) { fmt.Println("我为大家唱首歌",name) } func main1301() { //接口类型变量定义 var h Humaner2 var stu student13 = student13{"小吴",18,59} h = &stu h.sayhi() //接口类型变量定义 var p Personer p = &stu p.sayhi() p.sing("大碗面") } func main() { //接口类型变量定义 var h Humaner2 //子集 var p Personer //超集 var stu student13 = student13{"小吴",18,59} p = &stu //将一个接口赋值给另一个接口 //超集中包含所有子集的方法 h = p //ok h.sayhi() //子集不包含超集 //不能将子集赋值给超集 //p = h //err //p.sayhi() //p.sing("大碗面") }
- 如果用空接口作为变量类型,则该变量可以定义且接收任何类型(包括方法);如果是数组或者切片,也可以放入不通类型的数据
func main1401() { var i interface{} //接口类型可以接收任意类型的数据 //fmt.Println(i) fmt.Printf("%T\n",i) i = 10 fmt.Println(i) fmt.Printf("%T\n",i) i = 3.14 fmt.Println(i) fmt.Printf("%T\n",i) i = "Go" fmt.Println(i) fmt.Printf("%T\n",i) fmt.Println("aaa",11,3.14,'a') } func test14(){ fmt.Println("test14") } func main() { //空接口类型的切片 var i []interface{} fmt.Printf("%T\n",i) i = append(i,10,3.14,"aaa",test14) fmt.Println(i) for idx:=0; idx<len(i) ;idx++ { fmt.Println(i[idx]) } }