Go基础部分总结3

1.定义结构体
输入:

type Student struct {
	Name string
	Age  int
	Addr string
}

func main() {
	//结构体定义1
	var stu1 Student
	fmt.Println("stu1: ", stu1)
	//结构体定义2
	var stu2 = Student{}
	fmt.Println("stu2: ", stu2)
	//结构体定义3
	var stu3 *Student = new(Student) //x为指针,指针指向的为Student
	//var y *Student = &Student{}
	(*stu3).Name = "xx"
	stu2.Age = 18 //这样也没问题Go语言编译其底层对x.Age进行了处理(*x).Age
	fmt.Println("stu3: ", *stu3)
	//结构体定义4
	var stu4 *Student = &Student{}
	fmt.Println("stu4: ", *stu4)
}

输出:

stu1:  { 0 }
stu2:  { 0 }
stu3:  {xx 0 }
stu4:  { 0 }

2.结构体之间的相互转化1
输入:

type Student struct {
	Name string
}

type Persion struct {
	Name string
}

func main() {
	var s Student
	s.Name = "cc"
	var p Persion
	p.Name = "xx"
	s = Student(p)
	fmt.Println("输出转化后的s的值:", s)
	p = Persion(s) //引用传递
	fmt.Println("输出转化后的p的值:", p)
}

输出:

输出转化后的s的值: {xx}
输出转化后的p的值: {xx}

3.结构体之间的相互转化2
输入:

type Class struct {
	Name string
}
type Cla Class

func main() {
	var c1 Class
	c1.Name = "a"
	var c2 Cla
	fmt.Println("c1.Name=", c1.Name)
	fmt.Println("c2.Name=", c2.Name)
	c2 = Cla(c1)
	fmt.Println("转换后c1.Name=", c1.Name)
	fmt.Println("转换后c2.Name=", c2.Name)
}

输出:

c1.Name= a
c2.Name= 
转换后c1.Name= a
转换后c2.Name= a

4.方法与函数的区别
①方法需要绑定数据类型,函数不需要

type Student struct {
	Name string
}

// 方法
func (s Student) method1() {
	fmt.Println(s.Name)
}

// 函数
func function1(s Student) {
	fmt.Println(s.Name)
}

②调用方式不同
函数的调用:函数名(实参列表)
方法的调用:变量.方法名

func main() {
	var s Student
	s.Name = "xx"
	//函数的调用
	function1(s)
	//方法的调用
	s.method1()
}

③对于函数,传入参数类型严格指定,对于方法可以将值当作指针传入

type Student struct {
	Name string
}

// 方法1
func (s Student) method1() {
	fmt.Println(s.Name)
}

// 方法2
func (s *Student) method2() {
	fmt.Println(s.Name)
}

// 函数1
func function1(s Student) {
	fmt.Println(s.Name)
}

// 函数2
func function2(s *Student) {
	fmt.Println(s.Name)
}

func main() {
	var s Student
	s.Name = "xx"
	//函数的调用
	function1(s)
	//function1(&s)  这样传会报错
	//function2(&s)  正确方式
	//方法的调用
	s.method1()
	(&s).method1() //不会报错,虽然是指针类型调用,但还是值传递
	s.method2()    //不会报错,虽然是值类型调用,但还是引用传递
}

5.方法的调用
输入:

type Animal struct {
	Name string
	Food string
}

func (a Animal) Eat() {
	//结构体传入的对象为值传递
	fmt.Printf("Animal %v Eat %v ", a.Name, a.Food)
}
func main() {
	var a Animal
	a.Name = "Cat"
	a.Food = "Fish"
	a.Eat()
}

输出:

Animal Cat Eat Fish

6.通过指针在方法中实现引用传递
输入:

type Animal struct {
	Name string
}
//& 运算符用于获取变量的地址,而 * 运算符用于通过指针访问该地址处的值
func (a *Animal) Eat() {
	(*a).Name = "Dog"
	fmt.Println((*a).Name)
}
func main() {
	var a Animal
	a.Name = "Cat"
	(&a).Eat()
	fmt.Println(a.Name)
}

输出:

Dog
Dog

代码精简:
输入:

type Animal struct {
	Name string
}

func (a *Animal) Eat() {
	a.Name = "Dog"
	fmt.Println(a.Name)
}
func main() {
	var a Animal
	a.Name = "Cat"
	a.Eat()
	fmt.Println(a.Name)
}

输出:

Dog
Dog

7.方法使用注意事项
(1)方法的访问控制规则:
方法名 首字母小写 只能在本包中使用,方法名首字母大写,可以在本包和其他包访问!
(2)如果一个类型实现了String()方法,那么fmt.Println默认会调用这个变量的String()方法
输入:

type Student struct {
	Name string
	Age  int
}

func (s Student) String() string {
	sprintf := fmt.Sprintf("Student Name: %v ,Student Age: %v ", s.Name, s.Age)
	return sprintf
}

func main() {
	var stu Student
	stu.Name = "xx"
	stu.Age = 10
	fmt.Println(stu)
}

输出:

Student Name: xx ,Student Age: 10

8.跨包创建结构体实例
在这里插入图片描述

package model

type Student struct {
	Name string
	Age  int
}
package main

import (
	"fmt"
	"project/0625/model"
)

func main() {
	stu := model.Student{
		Name: "xx",
		Age:  18,
	}
	fmt.Println(stu)
}

注意:同方法访问规则类似
结构体名 首字母小写 只能在本包中使用,结构体名首字母大写,可以在本包和其他包访问!

9.解决首字母小写,跨包访问问题(类似JAVA中的构造方法)
输入:

package model

type Student struct {
	Name string
	Age  int
}

func CreateStudent(n string, a int) *Student {
	return &Student{n, a}
}
package main

import (
	"fmt"
	"project/0625/model"
)

func main() {
	stu := model.CreateStudent("xx", 18)
	fmt.Println(stu)
	fmt.Println(*stu)
}

输出:

&{xx 18}
{xx 18}

10.封装
在这里插入图片描述
输入:

package model

import "fmt"

type Student struct {
	Name string
	age  int
}

func NewStudent(name string, age int) *Student {
	return &Student{
		Name: name,
		age:  age,
	}
}

func (stu *Student) SetAge(age int) {
	if age > 0 && age < 100 {
		stu.age = age
	} else {
		fmt.Println("你输入的age有误")
	}
}
func (stu *Student) GetAge() int {
	return stu.age
}
package main

import (
	"fmt"
	"project/0626/model"
)

func main() {
	stu := model.NewStudent("xx", 18)
	fmt.Println(*stu)
	stu2 := model.Student{Name: "cc"}
	stu2.SetAge(18)
	fmt.Println(stu2.GetAge())
	fmt.Println(stu2)
}

输出:

{xx 18}
18
{cc 18}

11.继承
输入:

package main

import "fmt"

// 定义父结构体
type Animal struct {
	Age    int
	Weight float32
}

// 定义父结构体对应的方法
func (a *Animal) Eat() {
	fmt.Println("我是父结构体对应的方法")
}

// 定义子结构体
type Dog struct {
	Animal        //继承父结构体
	Breed  string //品种
}

// 定义子结构体对应的方法
func (d *Dog) Move() {
	fmt.Printf("我的品种是%v ,我今年%v岁了", d.Breed, d.Age)
}

func main() {
	dog := &Dog{
		Animal: Animal{
			Age:    20,
			Weight: 10.99,
		},
		Breed: "中华田园犬",
	}
	dog.Animal.Eat()
	dog.Move()
}

输出:

我是父结构体对应的方法
我的品种是中华田园犬 ,我今年20岁了

注意:结构体可以使用嵌套匿名结构体所有的字段和方法,即:首字母大写或者小写的字段、方法,都可以使用。

// 定义父结构体
type Animal struct {
	Age    int
	weight float32
}

// 定义父结构体对应的方法
func (a *Animal) eat() {
	fmt.Println("我是父结构体对应的方法")
}

12.匿名结构体字段、方法访问支持简化

//其他代码同上
dog.Animal.Eat() //结构体支持简化,等同于dog.Eat()

13.就近访问原则
当结构体与匿名结构体有相同的字段、方法时,访问这些字段、方法采取就近原则
输入:

package main

import "fmt"

// 定义父结构体
type Animal struct {
	Age    int
	Weight float32
}

// 定义父结构体对应的方法
func (a *Animal) Eat() {
	fmt.Println("我是父结构体对应的方法")
}

// 定义子结构体
type Dog struct {
	Animal //继承父结构体
	Age    int
	Weight float32
	Breed  string //品种
}

func (dog *Dog) Eat() {
	fmt.Println("我是Dog结构体对应的方法")
}

// 定义子结构体对应的方法
func (d *Dog) Move() {
	fmt.Printf("我的品种是%v ,我今年%v岁了", d.Breed, d.Age)
}

func main() {
	dog := &Dog{
		Animal: Animal{
			Age:    20,
			Weight: 10.99,
		},
		Age:    999,
		Weight: 999.99,
		Breed:  "中华田园犬",
	}
	fmt.Println(dog.Age) //就近原则  Age: 999,
	dog.Eat()
}

输出:

999
我是Dog结构体对应的方法

14.如果需要访问指定的字段或方法时,选择指定的结构体类型
15.Go支持多继承
一个结构体中有多个匿名结构体
输入:

package main

import "fmt"

type Cat struct {
	Name string
}
type Dog struct {
	Age int
}
type Animal struct {
	Cat
	Dog
}

func main() {
	animal := Animal{
		Cat{
			Name: "xx",
		},
		Dog{
			Age: 20,
		},
	}
	fmt.Println(animal.Name)
	fmt.Println(animal.Age)
}

输出:

xx
20

16.结构体中的字段可以是基本数据类型
输入:

package main

import "fmt"

type Student struct {
	Name string
	int
}
type Person struct {
	Name string
	stu  Student
}

/*
*
与

	type Person struct {
		Name string
		Student
	}

的区别:这种属于继承
而组合模式中只是三个字段
*/
func main() {
	person := Person{
		Name: "xx",
		stu: Student{
			Name: "cc",
			int:  1,
		},
	}
	fmt.Println(person.stu.Name)
	fmt.Println(person)
}

输出:

cc
{xx {cc 1}}

17.接口引入
输入:

package main

import "fmt"

type GetName interface {
	getName()
}
type Panda struct {
	name string
}

func (p Panda) getName() {
	fmt.Println("panda")
}

type Monkey struct {
	name string
}

func (m Monkey) getName() {
	fmt.Println("monkey")
}
func name(n GetName) {
	n.getName()
}
func main() {
	panda := new(Panda)
	name(panda)
	monkey := new(Monkey)
	name(monkey)
}

输出:

panda
monkey

(1)接口中可以定义一组方法,但不需要实现,不需要方法体。并且接口中不能包含任何变量。到某个自定义类型要使用的时候(实现接口的时候),再根据具体情况把这些方法具体实现出来。
(2)实现接口要实现所有的方法才是实现。
(3) Golang中的接口,不需要显式的实现接口。Golang中没有implement关键字。(Golang中实现接口是基于方法的,不是基于接口的)
例如:
A接口a,b方法
B接口a,b方法
C结构体实现了a,b方法,那么C实现了A接口,也可以说实现了B接口﹐(只要实现全部方法即可,和实际接口耦合性很低)
(4)接口目的是为了定义规范,具体由别人来实现即可。

18.接口相关注意事项
输入:

package main

import "fmt"

type GetName interface {
	getName()
}
type Panda struct {
	name string
}

func (p Panda) getName() {
	fmt.Println("panda")
}

type Monkey struct {
	name string
}

func (m Monkey) getName() {
	fmt.Println("monkey")
}
func name(n GetName) {
	n.getName()
}
func main() {
	panda := new(Panda)
	name(panda)
	monkey := new(Monkey)
	name(monkey)
	//不支持直接通过接口创建实例
	var g GetName
	fmt.Println(g) //输出:   <nil>
	g = panda      //将实现该接口的实例赋值后,可调用接口中的方法
	g.getName()
}

输出:

panda
monkey
<nil>
panda

19.一个结构体可以实现多个接口
输入:

package main

import "fmt"

type AgetPro interface {
	getAPro()
}
type BgetPro interface {
	getBPro()
}
type ProName struct {
	Name string
}

func (p *ProName) getAPro() {
	fmt.Println("getAPro() " + p.Name)
}
func (p *ProName) getBPro() {
	fmt.Println("getBPro() " + p.Name)
}
func main() {
	proName := ProName{"xC"}
	var apro AgetPro = &proName
	var bpro BgetPro = &proName
	apro.getAPro()
	bpro.getBPro()
}

输出:

getAPro() xC
getBPro() xC

20.多态参数与多态数组
输入:

package main

import "fmt"

type SayName interface {
	SayGoodsName()
}
type Goods1 struct {
	Name string
}
type Goods2 struct {
	Name string
}

func (g Goods1) SayGoodsName() {
	fmt.Println(g.Name)
}
func (g Goods2) SayGoodsName() {
	fmt.Println(g.Name)
}
func say(s SayName) {
	s.SayGoodsName()
}
func main() {
	//多态参数
	var g1 = Goods1{"xigua"}
	say(g1)
	var g2 = Goods1{"pingguo"}
	say(g2)
	//多态数组
	var arr [2]SayName
	arr[0] = Goods1{"xiangjiao"}
	arr[1] = Goods2{"caomei"}
	fmt.Println(arr)
}

输出:

xigua
pingguo
[{xiangjiao} {caomei}]

21.断言
一般用于单个结构体的判断,多个结构体的话自我感觉还是用Type Switch
输入:

package main

import "fmt"

type EatFood interface {
	FoodName()
}
type Food1 struct {
	Name string
}
type Food2 struct {
	Name string
}

func (f Food1) FoodName() {
	fmt.Println("Food1的名字为:", f.Name)
}
func (f Food1) ClearFood() {
	fmt.Println(f.Name, "已经洗过了")
}
func (f Food2) FoodName() {
	fmt.Println("Food2的名字为:", f.Name)
}
func eat(e EatFood) {
	e.FoodName()
	//断言
	//判断传过来的e是否为Food1类型,如果是则将其定义赋值给food1
	food1, flag := e.(Food1)
	if flag {
		food1.ClearFood()
	}
}
func main() {
	food1 := Food1{"黄瓜"}
	eat(food1)
	food2 := Food2{"番茄"}
	eat(food2)
}

输出:

Food1的名字为: 黄瓜
黄瓜 已经洗过了
Food2的名字为: 番茄

22.Type Switch
输入:

package main

import "fmt"

type EatFood interface {
	FoodName()
}
type Food1 struct {
	Name string
}
type Food2 struct {
	Name string
}

func (f Food1) FoodName() {
	fmt.Println("Food1的名字为:", f.Name)
}
func (f Food1) ClearFood() {
	fmt.Println(f.Name, "已经洗过了")
}
func (f Food2) FoodName() {
	fmt.Println("Food2的名字为:", f.Name)
}
func (f Food2) CutName() {
	fmt.Println(f.Name, "已经切过了")
}
func eat(e EatFood) {
	e.FoodName()
	//Type Switch
	switch e.(type) {
	case Food1:
		food1 := e.(Food1)
		food1.ClearFood()
	case Food2:
		food2 := e.(Food2)
		food2.CutName()
	default:
		fmt.Println("  wtf ?")
	}
}
func main() {
	food1 := Food1{"黄瓜"}
	eat(food1)
	food2 := Food2{"番茄"}
	eat(food2)
}

输出:

Food1的名字为: 黄瓜
黄瓜 已经洗过了
Food2的名字为: 番茄
番茄 已经切过了
  • 4
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值